<commit_before>/*
    This file is part of KXForms.

    Copyright (c) 2005,2006 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "reference.h"

#include <kdebug.h>

#include <QStringList>
#include <QMap>

using namespace KXForms;

Reference::Segment::Segment()
  : mCount( 1 ), mIsAttribute( false )
{
}

Reference::Segment::Segment( const QString &str )
{
  fromString( str );
}

Reference::Segment::Segment( const QString &name, int count )
{
  mName = name;
  mCount = count;
  mIsAttribute = false;
}

void Reference::Segment::setName( const QString &name )
{
  if ( name.startsWith( "@" ) ) {
    mName = name.mid( 1 );
    mIsAttribute = true;
  } else {
    mName = name;
    mIsAttribute = false;
  }
}

void Reference::Segment::fromString( const QString &str )
{
  int pos1 = str.indexOf( "[" );
  int pos2 = str.indexOf( "]" );

  int startPos;
  if ( str.startsWith( "@" ) ) {
    mIsAttribute = true;
    startPos = 1;
  } else {
    mIsAttribute = false;
    startPos = 0;
  }

  if ( pos1 >= 0 ) mName = str.mid( startPos, pos1 - startPos );
  else mName = str.mid( startPos );

  if ( pos1 >= 0 && pos2 > pos1 ) {
    QString count = str.mid( pos1 + 1, pos2 - pos1 - 1 );
    bool ok;
    mCount = count.toInt( &ok );
    if ( !ok ) kError() << "Illegal count in reference '" << str << "'" << endl;
  } else {
    mCount = 1;
  }
}

QString Reference::Segment::toString() const
{
  QString str;
  if ( mIsAttribute ) str += '@';
  str += mName;
  if ( mCount > 0 ) str += '[' + QString::number( mCount ) + ']';

  return str;
}

bool Reference::Segment::operator==( const Segment &s ) const
{
  return mName == s.mName && mCount == s.mCount &&
    mIsAttribute == s.mIsAttribute;
}

bool Reference::Segment::operator!=( const Segment &s ) const
{
  return !( *this == s );
}

bool Reference::Segment::isEmpty() const
{
  return mName.isEmpty();
}

Reference::Reference()
  : mValid( true )
{
}

Reference::Reference( const QString &str )
{
  fromString( str );
}

Reference::Reference( const char *str )
{
  fromString( str );
}

Reference &Reference::append( const Reference::Segment &segment )
{
  mSegments.append( segment );

  return *this;
}

Reference &Reference::append( const Reference &ref )
{
  Segment::List segments = ref.segments();
  Segment::List::ConstIterator it;
  for( it = segments.begin(); it != segments.end(); ++it ) {
    mSegments.append( *it );
  }

  return *this;
}

Reference Reference::operator+( const Reference &ref ) const
{
  Reference r = *this;
  return r.append( ref );
}

Reference Reference::operator+( const Reference::Segment &ref ) const
{
  Reference r = *this;
  return r.append( ref );
}

Reference::Segment::List Reference::segments() const
{
  return mSegments;
}

Reference::Segment &Reference::lastSegment()
{
  return mSegments.last();
}

const Reference::Segment &Reference::lastSegment() const
{
  return mSegments.last();
}

bool Reference::isAbsolute() const
{
  return mAbsolute;
}

bool Reference::isRelative() const{
  return !mAbsolute;
}

void Reference::fromString( const QString &str )
{
  mAbsolute = str.startsWith( "/" );

  QStringList s = str.split( "/" );
  QStringList::ConstIterator it;
  for( it = s.begin(); it != s.end(); ++it ) {
    mSegments.append( Segment( *it ) );
  }
}

QString Reference::toString() const
{
  QString str;
  Segment::List::ConstIterator it;
  for( it = mSegments.begin(); it != mSegments.end(); ++it ) {
    if ( !str.isEmpty() ) str += '/';
    str += (*it).toString();
  }
  if ( mAbsolute ) str.prepend( "/" );
  return str;
}

bool Reference::isValid() const
{
  return mValid;
}

bool Reference::isEmpty() const
{
  return mSegments.isEmpty();
}

bool Reference::operator==( const Reference &ref ) const
{
  if ( mAbsolute != ref.mAbsolute ) return false;

  Segment::List::ConstIterator it = mSegments.begin();
  Segment::List::ConstIterator it2 = ref.mSegments.begin();
  while( it != mSegments.end() && it2 != ref.mSegments.end() ) {
    if ( *it != *it2 ) return false;
    ++it;
    ++it2;
  }
  if ( it != mSegments.end() || it2 != ref.mSegments.end() ) return false;

  return true;
}

bool Reference::operator!=( const Reference &ref ) const
{
  return !( *this == ref );
}

Reference &Reference::operator=( const QString &str )
{
  fromString( str );
  return *this;
}

Reference &Reference::operator=( const char *str )
{
  fromString( str );
  return *this;
}

QDomElement Reference::apply( const QDomDocument &doc ) const
{
  QDomElement result;

  Reference::Segment::List::ConstIterator it;
  for( it = mSegments.begin(); it != mSegments.end(); ++it ) {
    Reference::Segment segment = *it;
    if ( result.isNull() ) {
      kDebug() << "ROOT" << endl;
      if ( doc.documentElement().tagName() == segment.name() ) {
        result = doc.documentElement();
        continue;
      } else {
        kError() << "Document element '" << doc.documentElement().tagName() <<
           "' isn't '" << segment.name() << "'" << endl;
        return QDomElement();
      }
    }

    QMap<QString, int> counts;
    QDomNode n;
    for( n = result.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e = n.toElement();
      int count = 1;
      QMap<QString, int>::ConstIterator itCount = counts.find( e.tagName() );
      if ( itCount != counts.end() ) count = itCount.value();
      if ( e.tagName() == segment.name() && count == segment.count() ) {
        result = e;
        break;
      }
      counts.insert( e.tagName(), ++count );
    }
    if ( n.isNull() ) {
      kError() << "Reference::apply(): Unable to find element '" <<
        segment.toString() << "'" << endl;
      return QDomElement();
    }
  }

  return result;
}

QDomElement Reference::applyElement( const QDomElement &context ) const
{
  kDebug() << "Reference::applyElement() " << toString() << " Context: "
    << context.tagName() << endl;

  QDomElement result = context;

  if ( mSegments.count() == 1 && lastSegment().name() == "." ) return result;

  Reference::Segment::List::ConstIterator it;
  for( it = mSegments.begin(); it != mSegments.end(); ++it ) {
    Reference::Segment segment = *it;

    kDebug() << "  Segment: " << segment.toString() << " Count: " <<
      segment.count() << endl;

    QMap<QString, int> counts;
    QDomNode n;
    for( n = result.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e = n.toElement();

      kDebug() << "  E: " << e.tagName() << endl;

      int count = 1;
      QMap<QString, int>::ConstIterator itCount = counts.find( e.tagName() );
      if ( itCount != counts.end() ) count = itCount.value();

      kDebug() << "  COUNT: " << count << endl;

      if ( e.tagName() == segment.name() && count == segment.count() ) {
        result = e;
        break;
      }
      counts.insert( e.tagName(), ++count );
    }
    if ( n.isNull() ) {
      kError() << "Reference::apply(): Unable to find element '" <<
        segment.toString() << "'" << endl;
      return QDomElement();
    }
  }

  return result;
}

QDomElement Reference::applyAttributeContext( const QDomElement &context ) const
{
  if ( mSegments.count() == 1 ) {
    return context;
  } else {
    Reference r;
    Segment::List::ConstIterator it = mSegments.begin();
    do {
      r.append( *it );
      ++it;
      Segment::List::ConstIterator it2 = it;
      if ( ++it2 == mSegments.end() ) break;
    } while( it != mSegments.end() );
    return r.applyElement( context );
  }
}

QString Reference::applyString( const QDomElement &context ) const
{
  Reference::Segment s = lastSegment();

  QString txt;
  if ( s.isAttribute() ) {
    QDomElement targetElement = applyAttributeContext( context );
    txt = targetElement.attribute( s.name() );
  } else {
    txt = applyElement( context ).text();
  }

  return txt;
}
<commit_msg>Fix segments creation.<commit_after>/*
    This file is part of KXForms.

    Copyright (c) 2005,2006 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "reference.h"

#include <kdebug.h>

#include <QStringList>
#include <QMap>

using namespace KXForms;

Reference::Segment::Segment()
  : mCount( 1 ), mIsAttribute( false )
{
}

Reference::Segment::Segment( const QString &str )
{
  fromString( str );
}

Reference::Segment::Segment( const QString &name, int count )
{
  mName = name;
  mCount = count;
  mIsAttribute = false;
}

void Reference::Segment::setName( const QString &name )
{
  if ( name.startsWith( "@" ) ) {
    mName = name.mid( 1 );
    mIsAttribute = true;
  } else {
    mName = name;
    mIsAttribute = false;
  }
}

void Reference::Segment::fromString( const QString &str )
{
  int pos1 = str.indexOf( "[" );
  int pos2 = str.indexOf( "]" );

  int startPos;
  if ( str.startsWith( "@" ) ) {
    mIsAttribute = true;
    startPos = 1;
  } else {
    mIsAttribute = false;
    startPos = 0;
  }

  if ( pos1 >= 0 ) mName = str.mid( startPos, pos1 - startPos );
  else mName = str.mid( startPos );

  if ( pos1 >= 0 && pos2 > pos1 ) {
    QString count = str.mid( pos1 + 1, pos2 - pos1 - 1 );
    bool ok;
    mCount = count.toInt( &ok );
    if ( !ok ) kError() << "Illegal count in reference '" << str << "'" << endl;
  } else {
    mCount = 1;
  }
}

QString Reference::Segment::toString() const
{
  QString str;
  if ( mIsAttribute ) str += '@';
  str += mName;
  if ( mCount > 0 ) str += '[' + QString::number( mCount ) + ']';

  return str;
}

bool Reference::Segment::operator==( const Segment &s ) const
{
  return mName == s.mName && mCount == s.mCount &&
    mIsAttribute == s.mIsAttribute;
}

bool Reference::Segment::operator!=( const Segment &s ) const
{
  return !( *this == s );
}

bool Reference::Segment::isEmpty() const
{
  return mName.isEmpty();
}

Reference::Reference()
  : mValid( true )
{
}

Reference::Reference( const QString &str )
{
  fromString( str );
}

Reference::Reference( const char *str )
{
  fromString( str );
}

Reference &Reference::append( const Reference::Segment &segment )
{
  mSegments.append( segment );

  return *this;
}

Reference &Reference::append( const Reference &ref )
{
  Segment::List segments = ref.segments();
  Segment::List::ConstIterator it;
  for( it = segments.begin(); it != segments.end(); ++it ) {
    mSegments.append( *it );
  }

  return *this;
}

Reference Reference::operator+( const Reference &ref ) const
{
  Reference r = *this;
  return r.append( ref );
}

Reference Reference::operator+( const Reference::Segment &ref ) const
{
  Reference r = *this;
  return r.append( ref );
}

Reference::Segment::List Reference::segments() const
{
  return mSegments;
}

Reference::Segment &Reference::lastSegment()
{
  return mSegments.last();
}

const Reference::Segment &Reference::lastSegment() const
{
  return mSegments.last();
}

bool Reference::isAbsolute() const
{
  return mAbsolute;
}

bool Reference::isRelative() const{
  return !mAbsolute;
}

void Reference::fromString( const QString &str )
{
  mAbsolute = str.startsWith( "/" );

  QStringList s = str.split( "/" );
  QStringList::ConstIterator it;
  for( it = s.begin(); it != s.end(); ++it ) {
    if( (*it).isEmpty() )
      continue;
    mSegments.append( Segment( *it ) );
  }
}

QString Reference::toString() const
{
  QString str;
  Segment::List::ConstIterator it;
  for( it = mSegments.begin(); it != mSegments.end(); ++it ) {
    if ( !str.isEmpty() ) str += '/';
    str += (*it).toString();
  }
  if ( mAbsolute ) str.prepend( "/" );
  return str;
}

bool Reference::isValid() const
{
  return mValid;
}

bool Reference::isEmpty() const
{
  return mSegments.isEmpty();
}

bool Reference::operator==( const Reference &ref ) const
{
  if ( mAbsolute != ref.mAbsolute ) return false;

  Segment::List::ConstIterator it = mSegments.begin();
  Segment::List::ConstIterator it2 = ref.mSegments.begin();
  while( it != mSegments.end() && it2 != ref.mSegments.end() ) {
    if ( *it != *it2 ) return false;
    ++it;
    ++it2;
  }
  if ( it != mSegments.end() || it2 != ref.mSegments.end() ) return false;

  return true;
}

bool Reference::operator!=( const Reference &ref ) const
{
  return !( *this == ref );
}

Reference &Reference::operator=( const QString &str )
{
  fromString( str );
  return *this;
}

Reference &Reference::operator=( const char *str )
{
  fromString( str );
  return *this;
}

QDomElement Reference::apply( const QDomDocument &doc ) const
{
  QDomElement result;

  Reference::Segment::List::ConstIterator it;
  for( it = mSegments.begin(); it != mSegments.end(); ++it ) {
    Reference::Segment segment = *it;
    if ( result.isNull() ) {
      kDebug() << "ROOT" << endl;
      if ( doc.documentElement().tagName() == segment.name() ) {
        result = doc.documentElement();
        continue;
      } else {
        kError() << "Document element '" << doc.documentElement().tagName() <<
           "' isn't '" << segment.name() << "'" << endl;
        return QDomElement();
      }
    }

    QMap<QString, int> counts;
    QDomNode n;
    for( n = result.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e = n.toElement();
      int count = 1;
      QMap<QString, int>::ConstIterator itCount = counts.find( e.tagName() );
      if ( itCount != counts.end() ) count = itCount.value();
      if ( e.tagName() == segment.name() && count == segment.count() ) {
        result = e;
        break;
      }
      counts.insert( e.tagName(), ++count );
    }
    if ( n.isNull() ) {
      kError() << "Reference::apply(): Unable to find element '" <<
        segment.toString() << "'" << endl;
      return QDomElement();
    }
  }

  return result;
}

QDomElement Reference::applyElement( const QDomElement &context ) const
{
  kDebug() << "Reference::applyElement() " << toString() << " Context: "
    << context.tagName() << endl;

  QDomElement result = context;

  if ( mSegments.count() == 1 && lastSegment().name() == "." ) return result;

  Reference::Segment::List::ConstIterator it;
  for( it = mSegments.begin(); it != mSegments.end(); ++it ) {
    Reference::Segment segment = *it;

    kDebug() << "  Segment: " << segment.toString() << " Count: " <<
      segment.count() << endl;

    QMap<QString, int> counts;
    QDomNode n;
    for( n = result.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e = n.toElement();

      kDebug() << "  E: " << e.tagName() << endl;

      int count = 1;
      QMap<QString, int>::ConstIterator itCount = counts.find( e.tagName() );
      if ( itCount != counts.end() ) count = itCount.value();

      kDebug() << "  COUNT: " << count << endl;

      if ( e.tagName() == segment.name() && count == segment.count() ) {
        result = e;
        break;
      }
      counts.insert( e.tagName(), ++count );
    }
    if ( n.isNull() ) {
      kError() << "Reference::apply(): Unable to find element '" <<
        segment.toString() << "'" << endl;
      return QDomElement();
    }
  }

  return result;
}

QDomElement Reference::applyAttributeContext( const QDomElement &context ) const
{
  if ( mSegments.count() == 1 ) {
    return context;
  } else {
    Reference r;
    Segment::List::ConstIterator it = mSegments.begin();
    do {
      r.append( *it );
      ++it;
      Segment::List::ConstIterator it2 = it;
      if ( ++it2 == mSegments.end() ) break;
    } while( it != mSegments.end() );
    return r.applyElement( context );
  }
}

QString Reference::applyString( const QDomElement &context ) const
{
  Reference::Segment s = lastSegment();

  QString txt;
  if ( s.isAttribute() ) {
    QDomElement targetElement = applyAttributeContext( context );
    txt = targetElement.attribute( s.name() );
  } else {
    txt = applyElement( context ).text();
  }

  return txt;
}
<|endoftext|>


<commit_before>#pragma once

#include "../base/assert.hpp"
#include "../base/base.hpp"
#include "../base/math.hpp"
#include "../base/matrix.hpp"
#include "../std/cmath.hpp"
#include "../std/sstream.hpp"
#include "../std/typeinfo.hpp"

#include "../base/start_mem_debug.hpp"

namespace m2
{
  template <typename T>
  class Point
  {
  public:
    T x, y;

    Point() {}
    Point(T x_, T y_) : x(x_), y(y_) {}
    template <typename U>
    Point(Point<U> const & u) : x(u.x), y(u.y) {}

    bool EqualDxDy(m2::Point<T> const & p, T eps) const
    {
      return ((fabs(x - p.x) < eps) && (fabs(y - p.y) < eps));
    }

    double Length(m2::Point<T> const & p) const
    {
      return sqrt(math::sqr(x - p.x) + math::sqr(y - p.y));
    }

    m2::Point<T> Move(T len, T ang) const
    {
      return m2::Point<T>(x + len * cos(ang), y + len * sin(ang));
    }

    Point<T> const & operator-=(Point<T> const & a)
    {
      x -= a.x;
      y -= a.y;
      return *this;
    }

    Point<T> const & operator+=(Point<T> const & a)
    {
      x += a.x;
      y += a.y;
      return *this;
    }

    template <typename U>
    Point<T> const & operator*=(U const & k)
    {
      x = static_cast<T>(x * k);
      y = static_cast<T>(y * k);
      return *this;
    }

    template <typename U>
    Point<T> const & operator=(Point<U> const & a)
    {
      x = static_cast<T>(a.x);
      y = static_cast<T>(a.y);
      return *this;
    }

    bool operator == (m2::Point<T> const & p) const
    {
      return x == p.x && y == p.y;
    }
    bool operator != (m2::Point<T> const & p) const
    {
      return !(*this == p);
    }
    m2::Point<T> operator + (m2::Point<T> const & pt) const
    {
      return m2::Point<T>(x + pt.x, y + pt.y);
    }
    m2::Point<T> operator - (m2::Point<T> const & pt) const
    {
      return m2::Point<T>(x - pt.x, y - pt.y);
    }
    m2::Point<T> operator -() const
    {
      return m2::Point<T>(-x, -y);
    }

    m2::Point<T> operator * (double scale) const
    {
      return m2::Point<T>(x * scale, y * scale);
    }

    m2::Point<T> const operator * (math::Matrix<T, 3, 3> const & m) const
    {
      m2::Point<T> res;
      res.x = x * m(0, 0) + y * m(1, 0) + m(2, 0);
      res.y = x * m(0, 1) + y * m(1, 1) + m(2, 1);
      return res;
    }

    m2::Point<T> operator / (double scale) const
    {
      return m2::Point<T>(x / scale, y / scale);
    }

    m2::Point<T> const & operator *= (math::Matrix<T, 3, 3> const & m)
    {
      T tempX = x;
      x = tempX * m(0, 0) + y * m(1, 0) + m(2, 0);
      y = tempX * m(0, 1) + y * m(1, 1) + m(2, 1);
      return *this;
    }

    void Rotate(double angle)
    {
      T cosAngle = cos(angle);
      T sinAngle = sin(angle);
      T oldX = x;
      x = cosAngle * oldX - sinAngle * y;
      y = sinAngle * oldX + cosAngle * y;
    }

    void Transform(m2::Point<T> const & org,
                   m2::Point<T> const & dx, m2::Point<T> const & dy)
    {
      T oldX = x;
      x = org.x + oldX * dx.x + y * dy.x;
      y = org.y + oldX * dx.y + y * dy.y;
    }
  };

  template <typename T>
  inline Point<T> const operator- (Point<T> const & a, Point<T> const & b)
  {
    return Point<T>(a.x - b.x, a.y - b.y);
  }

  template <typename T>
  inline Point<T> const operator+ (Point<T> const & a, Point<T> const & b)
  {
    return Point<T>(a.x + b.x, a.y + b.y);
  }

  // Dot product of a and b, equals to |a|*|b|*cos(angle_between_a_and_b).
  template <typename T>
  T const DotProduct(Point<T> const & a, Point<T> const & b)
  {
    return a.x * b.x + a.y * b.y;
  }

  // Value of cross product of a and b, equals to |a|*|b|*sin(angle_between_a_and_b).
  template <typename T>
  T const CrossProduct(Point<T> const & a, Point<T> const & b)
  {
    return a.y * b.x - a.x * b.y;
  }

  template <typename T>
      Point<T> const Rotate(Point<T> const & pt, T a)
  {
    Point<T> res(pt);
    res.Rotate(a);
    return res;
  }

  template <typename T, typename U>
      Point<T> const Shift(Point<T> const & pt, U const & dx, U const & dy)
  {
    return Point<T>(pt.x + dx, pt.y + dy);
  }

  template <typename T, typename U>
      Point<T> const Shift(Point<T> const & pt, Point<U> const & offset)
  {
    return Shift(pt, offset.x, offset.y);
  }

  template <typename T>
  bool IsPointStrictlyInsideTriangle(Point<T> const & p,
                                     Point<T> const & a, Point<T> const & b, Point<T> const & c)
  {
    T const cpab = CrossProduct(b - a, p - a);
    T const cpbc = CrossProduct(c - b, p - b);
    T const cpca = CrossProduct(a - c, p - c);
    return (cpab < 0 && cpbc < 0 && cpca < 0) || (cpab > 0 && cpbc > 0 && cpca > 0);
  }

  template <typename T>
  bool SegmentsIntersect(Point<T> const & a, Point<T> const & b,
                         Point<T> const & c, Point<T> const & d)
  {
    return
        max(a.x, b.x) >= min(c.x, d.x) &&
        min(a.x, b.x) <= max(c.x, d.x) &&
        max(a.y, b.y) >= min(c.y, d.y) &&
        min(a.y, b.y) <= max(c.y, d.y) &&
        CrossProduct(c - a, b - a) * CrossProduct(d - a, b - a) <= 0 &&
        CrossProduct(a - c, d - c) * CrossProduct(b - c, d - c) <= 0;
  }

  template <typename T> string debug_print(m2::Point<T> const & p)
  {
    ostringstream out;
    out << "m2::Point<" << typeid(T).name() << ">(" << p.x << ", " << p.y << ")";
    return out.str();
  }

  template <typename T> bool AlmostEqual(m2::Point<T> const & a, m2::Point<T> const & b)
  {
    return my::AlmostEqual(a.x, b.x) && my::AlmostEqual(a.y, b.y);
  }

  typedef Point<float> PointF;
  typedef Point<double> PointD;
  typedef Point<uint32_t> PointU;
  typedef Point<int> PointI;
}

#include "../base/stop_mem_debug.hpp"
<commit_msg>Fix CrossProduct().<commit_after>#pragma once

#include "../base/assert.hpp"
#include "../base/base.hpp"
#include "../base/math.hpp"
#include "../base/matrix.hpp"
#include "../std/cmath.hpp"
#include "../std/sstream.hpp"
#include "../std/typeinfo.hpp"

#include "../base/start_mem_debug.hpp"

namespace m2
{
  template <typename T>
  class Point
  {
  public:
    T x, y;

    Point() {}
    Point(T x_, T y_) : x(x_), y(y_) {}
    template <typename U>
    Point(Point<U> const & u) : x(u.x), y(u.y) {}

    bool EqualDxDy(m2::Point<T> const & p, T eps) const
    {
      return ((fabs(x - p.x) < eps) && (fabs(y - p.y) < eps));
    }

    double Length(m2::Point<T> const & p) const
    {
      return sqrt(math::sqr(x - p.x) + math::sqr(y - p.y));
    }

    m2::Point<T> Move(T len, T ang) const
    {
      return m2::Point<T>(x + len * cos(ang), y + len * sin(ang));
    }

    Point<T> const & operator-=(Point<T> const & a)
    {
      x -= a.x;
      y -= a.y;
      return *this;
    }

    Point<T> const & operator+=(Point<T> const & a)
    {
      x += a.x;
      y += a.y;
      return *this;
    }

    template <typename U>
    Point<T> const & operator*=(U const & k)
    {
      x = static_cast<T>(x * k);
      y = static_cast<T>(y * k);
      return *this;
    }

    template <typename U>
    Point<T> const & operator=(Point<U> const & a)
    {
      x = static_cast<T>(a.x);
      y = static_cast<T>(a.y);
      return *this;
    }

    bool operator == (m2::Point<T> const & p) const
    {
      return x == p.x && y == p.y;
    }
    bool operator != (m2::Point<T> const & p) const
    {
      return !(*this == p);
    }
    m2::Point<T> operator + (m2::Point<T> const & pt) const
    {
      return m2::Point<T>(x + pt.x, y + pt.y);
    }
    m2::Point<T> operator - (m2::Point<T> const & pt) const
    {
      return m2::Point<T>(x - pt.x, y - pt.y);
    }
    m2::Point<T> operator -() const
    {
      return m2::Point<T>(-x, -y);
    }

    m2::Point<T> operator * (double scale) const
    {
      return m2::Point<T>(x * scale, y * scale);
    }

    m2::Point<T> const operator * (math::Matrix<T, 3, 3> const & m) const
    {
      m2::Point<T> res;
      res.x = x * m(0, 0) + y * m(1, 0) + m(2, 0);
      res.y = x * m(0, 1) + y * m(1, 1) + m(2, 1);
      return res;
    }

    m2::Point<T> operator / (double scale) const
    {
      return m2::Point<T>(x / scale, y / scale);
    }

    m2::Point<T> const & operator *= (math::Matrix<T, 3, 3> const & m)
    {
      T tempX = x;
      x = tempX * m(0, 0) + y * m(1, 0) + m(2, 0);
      y = tempX * m(0, 1) + y * m(1, 1) + m(2, 1);
      return *this;
    }

    void Rotate(double angle)
    {
      T cosAngle = cos(angle);
      T sinAngle = sin(angle);
      T oldX = x;
      x = cosAngle * oldX - sinAngle * y;
      y = sinAngle * oldX + cosAngle * y;
    }

    void Transform(m2::Point<T> const & org,
                   m2::Point<T> const & dx, m2::Point<T> const & dy)
    {
      T oldX = x;
      x = org.x + oldX * dx.x + y * dy.x;
      y = org.y + oldX * dx.y + y * dy.y;
    }
  };

  template <typename T>
  inline Point<T> const operator- (Point<T> const & a, Point<T> const & b)
  {
    return Point<T>(a.x - b.x, a.y - b.y);
  }

  template <typename T>
  inline Point<T> const operator+ (Point<T> const & a, Point<T> const & b)
  {
    return Point<T>(a.x + b.x, a.y + b.y);
  }

  // Dot product of a and b, equals to |a|*|b|*cos(angle_between_a_and_b).
  template <typename T>
  T const DotProduct(Point<T> const & a, Point<T> const & b)
  {
    return a.x * b.x + a.y * b.y;
  }

  // Value of cross product of a and b, equals to |a|*|b|*sin(angle_between_a_and_b).
  template <typename T>
  T const CrossProduct(Point<T> const & a, Point<T> const & b)
  {
    return a.x * b.y - a.y * b.x;
  }

  template <typename T>
      Point<T> const Rotate(Point<T> const & pt, T a)
  {
    Point<T> res(pt);
    res.Rotate(a);
    return res;
  }

  template <typename T, typename U>
      Point<T> const Shift(Point<T> const & pt, U const & dx, U const & dy)
  {
    return Point<T>(pt.x + dx, pt.y + dy);
  }

  template <typename T, typename U>
      Point<T> const Shift(Point<T> const & pt, Point<U> const & offset)
  {
    return Shift(pt, offset.x, offset.y);
  }

  template <typename T>
  bool IsPointStrictlyInsideTriangle(Point<T> const & p,
                                     Point<T> const & a, Point<T> const & b, Point<T> const & c)
  {
    T const cpab = CrossProduct(b - a, p - a);
    T const cpbc = CrossProduct(c - b, p - b);
    T const cpca = CrossProduct(a - c, p - c);
    return (cpab < 0 && cpbc < 0 && cpca < 0) || (cpab > 0 && cpbc > 0 && cpca > 0);
  }

  template <typename T>
  bool SegmentsIntersect(Point<T> const & a, Point<T> const & b,
                         Point<T> const & c, Point<T> const & d)
  {
    return
        max(a.x, b.x) >= min(c.x, d.x) &&
        min(a.x, b.x) <= max(c.x, d.x) &&
        max(a.y, b.y) >= min(c.y, d.y) &&
        min(a.y, b.y) <= max(c.y, d.y) &&
        CrossProduct(c - a, b - a) * CrossProduct(d - a, b - a) <= 0 &&
        CrossProduct(a - c, d - c) * CrossProduct(b - c, d - c) <= 0;
  }

  template <typename T> string debug_print(m2::Point<T> const & p)
  {
    ostringstream out;
    out << "m2::Point<" << typeid(T).name() << ">(" << p.x << ", " << p.y << ")";
    return out.str();
  }

  template <typename T> bool AlmostEqual(m2::Point<T> const & a, m2::Point<T> const & b)
  {
    return my::AlmostEqual(a.x, b.x) && my::AlmostEqual(a.y, b.y);
  }

  typedef Point<float> PointF;
  typedef Point<double> PointD;
  typedef Point<uint32_t> PointU;
  typedef Point<int> PointI;
}

#include "../base/stop_mem_debug.hpp"
<|endoftext|>


<commit_before>//===- CGSCCPassManagerTest.cpp -------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"

using namespace llvm;

namespace {

class TestModuleAnalysis {
public:
  struct Result {
    Result(int Count) : FunctionCount(Count) {}
    int FunctionCount;
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestModuleAnalysis"; }

  TestModuleAnalysis(int &Runs) : Runs(Runs) {}

  Result run(Module &M, ModuleAnalysisManager &AM) {
    ++Runs;
    return Result(M.size());
  }

private:
  static char PassID;

  int &Runs;
};

char TestModuleAnalysis::PassID;

class TestSCCAnalysis {
public:
  struct Result {
    Result(int Count) : FunctionCount(Count) {}
    int FunctionCount;
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestSCCAnalysis"; }

  TestSCCAnalysis(int &Runs) : Runs(Runs) {}

  Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
    ++Runs;
    return Result(C.size());
  }

private:
  static char PassID;

  int &Runs;
};

char TestSCCAnalysis::PassID;

class TestFunctionAnalysis {
public:
  struct Result {
    Result(int Count) : InstructionCount(Count) {}
    int InstructionCount;
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestFunctionAnalysis"; }

  TestFunctionAnalysis(int &Runs) : Runs(Runs) {}

  Result run(Function &F, FunctionAnalysisManager &AM) {
    ++Runs;
    int Count = 0;
    for (Instruction &I : instructions(F)) {
      (void)I;
      ++Count;
    }
    return Result(Count);
  }

private:
  static char PassID;

  int &Runs;
};

char TestFunctionAnalysis::PassID;

class TestImmutableFunctionAnalysis {
public:
  struct Result {
    bool invalidate(Function &, const PreservedAnalyses &) { return false; }
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestImmutableFunctionAnalysis"; }

  TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {}

  Result run(Function &F, FunctionAnalysisManager &AM) {
    ++Runs;
    return Result();
  }

private:
  static char PassID;

  int &Runs;
};

char TestImmutableFunctionAnalysis::PassID;

struct TestModulePass {
  TestModulePass(int &RunCount) : RunCount(RunCount) {}

  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
    ++RunCount;
    (void)AM.getResult<TestModuleAnalysis>(M);
    return PreservedAnalyses::all();
  }

  static StringRef name() { return "TestModulePass"; }

  int &RunCount;
};

struct TestSCCPass {
  TestSCCPass(int &RunCount, int &AnalyzedInstrCount,
              int &AnalyzedSCCFunctionCount, int &AnalyzedModuleFunctionCount,
              bool OnlyUseCachedResults = false)
      : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
        AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount),
        AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount),
        OnlyUseCachedResults(OnlyUseCachedResults) {}

  PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
    ++RunCount;

    const ModuleAnalysisManager &MAM =
        AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager();
    FunctionAnalysisManager &FAM =
        AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
    if (TestModuleAnalysis::Result *TMA =
            MAM.getCachedResult<TestModuleAnalysis>(
                *C.begin()->getFunction().getParent()))
      AnalyzedModuleFunctionCount += TMA->FunctionCount;

    if (OnlyUseCachedResults) {
      // Hack to force the use of the cached interface.
      if (TestSCCAnalysis::Result *AR = AM.getCachedResult<TestSCCAnalysis>(C))
        AnalyzedSCCFunctionCount += AR->FunctionCount;
      for (LazyCallGraph::Node &N : C)
        if (TestFunctionAnalysis::Result *FAR =
                FAM.getCachedResult<TestFunctionAnalysis>(N.getFunction()))
          AnalyzedInstrCount += FAR->InstructionCount;
    } else {
      // Typical path just runs the analysis as needed.
      TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C);
      AnalyzedSCCFunctionCount += AR.FunctionCount;
      for (LazyCallGraph::Node &N : C) {
        TestFunctionAnalysis::Result &FAR =
            FAM.getResult<TestFunctionAnalysis>(N.getFunction());
        AnalyzedInstrCount += FAR.InstructionCount;

        // Just ensure we get the immutable results.
        (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
      }
    }

    return PreservedAnalyses::all();
  }

  static StringRef name() { return "TestSCCPass"; }

  int &RunCount;
  int &AnalyzedInstrCount;
  int &AnalyzedSCCFunctionCount;
  int &AnalyzedModuleFunctionCount;
  bool OnlyUseCachedResults;
};

struct TestFunctionPass {
  TestFunctionPass(int &RunCount) : RunCount(RunCount) {}

  PreservedAnalyses run(Function &F, AnalysisManager<Function> &) {
    ++RunCount;
    return PreservedAnalyses::none();
  }

  static StringRef name() { return "TestFunctionPass"; }

  int &RunCount;
};

std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
  SMDiagnostic Err;
  return parseAssemblyString(IR, Err, C);
}

class CGSCCPassManagerTest : public ::testing::Test {
protected:
  LLVMContext Context;
  std::unique_ptr<Module> M;

public:
  CGSCCPassManagerTest()
      : M(parseIR(Context, "define void @f() {\n"
                           "entry:\n"
                           "  call void @g()\n"
                           "  call void @h1()\n"
                           "  ret void\n"
                           "}\n"
                           "define void @g() {\n"
                           "entry:\n"
                           "  call void @g()\n"
                           "  call void @x()\n"
                           "  ret void\n"
                           "}\n"
                           "define void @h1() {\n"
                           "entry:\n"
                           "  call void @h2()\n"
                           "  ret void\n"
                           "}\n"
                           "define void @h2() {\n"
                           "entry:\n"
                           "  call void @h3()\n"
                           "  call void @x()\n"
                           "  ret void\n"
                           "}\n"
                           "define void @h3() {\n"
                           "entry:\n"
                           "  call void @h1()\n"
                           "  ret void\n"
                           "}\n"
                           "define void @x() {\n"
                           "entry:\n"
                           "  ret void\n"
                           "}\n")) {}
};

TEST_F(CGSCCPassManagerTest, Basic) {
  FunctionAnalysisManager FAM(/*DebugLogging*/ true);
  int FunctionAnalysisRuns = 0;
  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
  int ImmutableFunctionAnalysisRuns = 0;
  FAM.registerPass([&] {
    return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
  });

  CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
  int SCCAnalysisRuns = 0;
  CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });

  ModuleAnalysisManager MAM(/*DebugLogging*/ true);
  int ModuleAnalysisRuns = 0;
  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
  MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });

  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
  MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
  CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
  CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
  FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });

  ModulePassManager MPM(/*DebugLogging*/ true);
  int ModulePassRunCount1 = 0;
  MPM.addPass(TestModulePass(ModulePassRunCount1));

  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
  int SCCPassRunCount1 = 0;
  int AnalyzedInstrCount1 = 0;
  int AnalyzedSCCFunctionCount1 = 0;
  int AnalyzedModuleFunctionCount1 = 0;
  CGPM1.addPass(TestSCCPass(SCCPassRunCount1, AnalyzedInstrCount1,
                            AnalyzedSCCFunctionCount1,
                            AnalyzedModuleFunctionCount1));

  FunctionPassManager FPM1(/*DebugLogging*/ true);
  int FunctionPassRunCount1 = 0;
  FPM1.addPass(TestFunctionPass(FunctionPassRunCount1));
  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));

  MPM.run(*M, MAM);

  EXPECT_EQ(1, ModulePassRunCount1);

  EXPECT_EQ(1, ModuleAnalysisRuns);
  EXPECT_EQ(4, SCCAnalysisRuns);
  EXPECT_EQ(6, FunctionAnalysisRuns);
  EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);

  EXPECT_EQ(4, SCCPassRunCount1);
  EXPECT_EQ(14, AnalyzedInstrCount1);
  EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
  EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
}

}
<commit_msg>[PM] Sink the module parsing from the fixture to the test as subsequent tests will want different IR.<commit_after>//===- CGSCCPassManagerTest.cpp -------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"

using namespace llvm;

namespace {

class TestModuleAnalysis {
public:
  struct Result {
    Result(int Count) : FunctionCount(Count) {}
    int FunctionCount;
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestModuleAnalysis"; }

  TestModuleAnalysis(int &Runs) : Runs(Runs) {}

  Result run(Module &M, ModuleAnalysisManager &AM) {
    ++Runs;
    return Result(M.size());
  }

private:
  static char PassID;

  int &Runs;
};

char TestModuleAnalysis::PassID;

class TestSCCAnalysis {
public:
  struct Result {
    Result(int Count) : FunctionCount(Count) {}
    int FunctionCount;
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestSCCAnalysis"; }

  TestSCCAnalysis(int &Runs) : Runs(Runs) {}

  Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
    ++Runs;
    return Result(C.size());
  }

private:
  static char PassID;

  int &Runs;
};

char TestSCCAnalysis::PassID;

class TestFunctionAnalysis {
public:
  struct Result {
    Result(int Count) : InstructionCount(Count) {}
    int InstructionCount;
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestFunctionAnalysis"; }

  TestFunctionAnalysis(int &Runs) : Runs(Runs) {}

  Result run(Function &F, FunctionAnalysisManager &AM) {
    ++Runs;
    int Count = 0;
    for (Instruction &I : instructions(F)) {
      (void)I;
      ++Count;
    }
    return Result(Count);
  }

private:
  static char PassID;

  int &Runs;
};

char TestFunctionAnalysis::PassID;

class TestImmutableFunctionAnalysis {
public:
  struct Result {
    bool invalidate(Function &, const PreservedAnalyses &) { return false; }
  };

  static void *ID() { return (void *)&PassID; }
  static StringRef name() { return "TestImmutableFunctionAnalysis"; }

  TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {}

  Result run(Function &F, FunctionAnalysisManager &AM) {
    ++Runs;
    return Result();
  }

private:
  static char PassID;

  int &Runs;
};

char TestImmutableFunctionAnalysis::PassID;

struct TestModulePass {
  TestModulePass(int &RunCount) : RunCount(RunCount) {}

  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
    ++RunCount;
    (void)AM.getResult<TestModuleAnalysis>(M);
    return PreservedAnalyses::all();
  }

  static StringRef name() { return "TestModulePass"; }

  int &RunCount;
};

struct TestSCCPass {
  TestSCCPass(int &RunCount, int &AnalyzedInstrCount,
              int &AnalyzedSCCFunctionCount, int &AnalyzedModuleFunctionCount,
              bool OnlyUseCachedResults = false)
      : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
        AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount),
        AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount),
        OnlyUseCachedResults(OnlyUseCachedResults) {}

  PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
    ++RunCount;

    const ModuleAnalysisManager &MAM =
        AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager();
    FunctionAnalysisManager &FAM =
        AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
    if (TestModuleAnalysis::Result *TMA =
            MAM.getCachedResult<TestModuleAnalysis>(
                *C.begin()->getFunction().getParent()))
      AnalyzedModuleFunctionCount += TMA->FunctionCount;

    if (OnlyUseCachedResults) {
      // Hack to force the use of the cached interface.
      if (TestSCCAnalysis::Result *AR = AM.getCachedResult<TestSCCAnalysis>(C))
        AnalyzedSCCFunctionCount += AR->FunctionCount;
      for (LazyCallGraph::Node &N : C)
        if (TestFunctionAnalysis::Result *FAR =
                FAM.getCachedResult<TestFunctionAnalysis>(N.getFunction()))
          AnalyzedInstrCount += FAR->InstructionCount;
    } else {
      // Typical path just runs the analysis as needed.
      TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C);
      AnalyzedSCCFunctionCount += AR.FunctionCount;
      for (LazyCallGraph::Node &N : C) {
        TestFunctionAnalysis::Result &FAR =
            FAM.getResult<TestFunctionAnalysis>(N.getFunction());
        AnalyzedInstrCount += FAR.InstructionCount;

        // Just ensure we get the immutable results.
        (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
      }
    }

    return PreservedAnalyses::all();
  }

  static StringRef name() { return "TestSCCPass"; }

  int &RunCount;
  int &AnalyzedInstrCount;
  int &AnalyzedSCCFunctionCount;
  int &AnalyzedModuleFunctionCount;
  bool OnlyUseCachedResults;
};

struct TestFunctionPass {
  TestFunctionPass(int &RunCount) : RunCount(RunCount) {}

  PreservedAnalyses run(Function &F, AnalysisManager<Function> &) {
    ++RunCount;
    return PreservedAnalyses::none();
  }

  static StringRef name() { return "TestFunctionPass"; }

  int &RunCount;
};

std::unique_ptr<Module> parseIR(const char *IR) {
  // We just use a static context here. This is never called from multiple
  // threads so it is harmless no matter how it is implemented. We just need
  // the context to outlive the module which it does.
  static LLVMContext C;
  SMDiagnostic Err;
  return parseAssemblyString(IR, Err, C);
}

TEST(CGSCCPassManagerTest, Basic) {
  auto M = parseIR("define void @f() {\n"
                   "entry:\n"
                   "  call void @g()\n"
                   "  call void @h1()\n"
                   "  ret void\n"
                   "}\n"
                   "define void @g() {\n"
                   "entry:\n"
                   "  call void @g()\n"
                   "  call void @x()\n"
                   "  ret void\n"
                   "}\n"
                   "define void @h1() {\n"
                   "entry:\n"
                   "  call void @h2()\n"
                   "  ret void\n"
                   "}\n"
                   "define void @h2() {\n"
                   "entry:\n"
                   "  call void @h3()\n"
                   "  call void @x()\n"
                   "  ret void\n"
                   "}\n"
                   "define void @h3() {\n"
                   "entry:\n"
                   "  call void @h1()\n"
                   "  ret void\n"
                   "}\n"
                   "define void @x() {\n"
                   "entry:\n"
                   "  ret void\n"
                   "}\n");
  FunctionAnalysisManager FAM(/*DebugLogging*/ true);
  int FunctionAnalysisRuns = 0;
  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
  int ImmutableFunctionAnalysisRuns = 0;
  FAM.registerPass([&] {
    return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
  });

  CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
  int SCCAnalysisRuns = 0;
  CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });

  ModuleAnalysisManager MAM(/*DebugLogging*/ true);
  int ModuleAnalysisRuns = 0;
  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
  MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });

  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
  MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
  CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
  CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
  FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });

  ModulePassManager MPM(/*DebugLogging*/ true);
  int ModulePassRunCount1 = 0;
  MPM.addPass(TestModulePass(ModulePassRunCount1));

  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
  int SCCPassRunCount1 = 0;
  int AnalyzedInstrCount1 = 0;
  int AnalyzedSCCFunctionCount1 = 0;
  int AnalyzedModuleFunctionCount1 = 0;
  CGPM1.addPass(TestSCCPass(SCCPassRunCount1, AnalyzedInstrCount1,
                            AnalyzedSCCFunctionCount1,
                            AnalyzedModuleFunctionCount1));

  FunctionPassManager FPM1(/*DebugLogging*/ true);
  int FunctionPassRunCount1 = 0;
  FPM1.addPass(TestFunctionPass(FunctionPassRunCount1));
  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));

  MPM.run(*M, MAM);

  EXPECT_EQ(1, ModulePassRunCount1);

  EXPECT_EQ(1, ModuleAnalysisRuns);
  EXPECT_EQ(4, SCCAnalysisRuns);
  EXPECT_EQ(6, FunctionAnalysisRuns);
  EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);

  EXPECT_EQ(4, SCCPassRunCount1);
  EXPECT_EQ(14, AnalyzedInstrCount1);
  EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
  EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
}

}
<|endoftext|>


<commit_before>//===- unittests/Frontend/CompilerInstanceTest.cpp - CI tests -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ToolOutputFile.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace clang;

namespace {

TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
  // Create a temporary VFS overlay yaml file.
  int FD;
  SmallString<256> FileName;
  ASSERT_FALSE(sys::fs::createTemporaryFile("vfs", "yaml", FD, FileName));
  ToolOutputFile File(FileName, FD);

  SmallString<256> CurrentPath;
  sys::fs::current_path(CurrentPath);
  sys::fs::make_absolute(CurrentPath, FileName);

  // Mount the VFS file itself on the path 'virtual.file'. Makes this test
  // a bit shorter than creating a new dummy file just for this purpose.
  const std::string CurrentPathStr = CurrentPath.str();
  const std::string FileNameStr = FileName.str();
  const char *VFSYaml = "{ 'version': 0, 'roots': [\n"
                        "  { 'name': '%s',\n"
                        "    'type': 'directory',\n"
                        "    'contents': [\n"
                        "      { 'name': 'vfs-virtual.file', 'type': 'file',\n"
                        "        'external-contents': '%s'\n"
                        "      }\n"
                        "    ]\n"
                        "  }\n"
                        "]}\n";
  File.os() << format(VFSYaml, CurrentPathStr.c_str(), FileName.c_str());
  File.os().flush();

  // Create a CompilerInvocation that uses this overlay file.
  const std::string VFSArg = "-ivfsoverlay" + FileNameStr;
  const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"};

  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
      CompilerInstance::createDiagnostics(new DiagnosticOptions());

  std::shared_ptr<CompilerInvocation> CInvok =
      createInvocationFromCommandLine(Args, Diags);

  if (!CInvok)
    FAIL() << "could not create compiler invocation";
  // Create a minimal CompilerInstance which should use the VFS we specified
  // in the CompilerInvocation (as we don't explicitly set our own).
  CompilerInstance Instance;
  Instance.setDiagnostics(Diags.get());
  Instance.setInvocation(CInvok);
  Instance.createFileManager();

  // Check if the virtual file exists which means that our VFS is used by the
  // CompilerInstance.
  ASSERT_TRUE(Instance.getFileManager().getFile("vfs-virtual.file"));
}

TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
  auto DiagOpts = new DiagnosticOptions();

  // Create the diagnostic engine with unowned consumer.
  std::string DiagnosticOutput;
  llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
  auto DiagPrinter = llvm::make_unique<TextDiagnosticPrinter>(
      DiagnosticsOS, new DiagnosticOptions());
  CompilerInstance Instance;
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags = Instance.createDiagnostics(
      DiagOpts, DiagPrinter.get(), /*ShouldOwnClient=*/false);

  Diags->Report(diag::err_expected) << "no crash";
  ASSERT_EQ(DiagnosticsOS.str(), "error: expected no crash\n");
}

} // anonymous namespace
<commit_msg>[test] Reinstate the assignment to the diagnostic log in the unittest from r363009<commit_after>//===- unittests/Frontend/CompilerInstanceTest.cpp - CI tests -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ToolOutputFile.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace clang;

namespace {

TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
  // Create a temporary VFS overlay yaml file.
  int FD;
  SmallString<256> FileName;
  ASSERT_FALSE(sys::fs::createTemporaryFile("vfs", "yaml", FD, FileName));
  ToolOutputFile File(FileName, FD);

  SmallString<256> CurrentPath;
  sys::fs::current_path(CurrentPath);
  sys::fs::make_absolute(CurrentPath, FileName);

  // Mount the VFS file itself on the path 'virtual.file'. Makes this test
  // a bit shorter than creating a new dummy file just for this purpose.
  const std::string CurrentPathStr = CurrentPath.str();
  const std::string FileNameStr = FileName.str();
  const char *VFSYaml = "{ 'version': 0, 'roots': [\n"
                        "  { 'name': '%s',\n"
                        "    'type': 'directory',\n"
                        "    'contents': [\n"
                        "      { 'name': 'vfs-virtual.file', 'type': 'file',\n"
                        "        'external-contents': '%s'\n"
                        "      }\n"
                        "    ]\n"
                        "  }\n"
                        "]}\n";
  File.os() << format(VFSYaml, CurrentPathStr.c_str(), FileName.c_str());
  File.os().flush();

  // Create a CompilerInvocation that uses this overlay file.
  const std::string VFSArg = "-ivfsoverlay" + FileNameStr;
  const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"};

  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
      CompilerInstance::createDiagnostics(new DiagnosticOptions());

  std::shared_ptr<CompilerInvocation> CInvok =
      createInvocationFromCommandLine(Args, Diags);

  if (!CInvok)
    FAIL() << "could not create compiler invocation";
  // Create a minimal CompilerInstance which should use the VFS we specified
  // in the CompilerInvocation (as we don't explicitly set our own).
  CompilerInstance Instance;
  Instance.setDiagnostics(Diags.get());
  Instance.setInvocation(CInvok);
  Instance.createFileManager();

  // Check if the virtual file exists which means that our VFS is used by the
  // CompilerInstance.
  ASSERT_TRUE(Instance.getFileManager().getFile("vfs-virtual.file"));
}

TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
  auto DiagOpts = new DiagnosticOptions();
  // Tell the diagnostics engine to emit the diagnostic log to STDERR. This
  // ensures that a chained diagnostic consumer is created so that the test can
  // exercise the unowned diagnostic consumer in a chained consumer.
  DiagOpts->DiagnosticLogFile = "-";

  // Create the diagnostic engine with unowned consumer.
  std::string DiagnosticOutput;
  llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
  auto DiagPrinter = llvm::make_unique<TextDiagnosticPrinter>(
      DiagnosticsOS, new DiagnosticOptions());
  CompilerInstance Instance;
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags = Instance.createDiagnostics(
      DiagOpts, DiagPrinter.get(), /*ShouldOwnClient=*/false);

  Diags->Report(diag::err_expected) << "no crash";
  ASSERT_EQ(DiagnosticsOS.str(), "error: expected no crash\n");
}

} // anonymous namespace
<|endoftext|>


<commit_before>#include <tests/Base.hh>

#include <aleph/distances/Wasserstein.hh>

#include <aleph/persistenceDiagrams/Mean.hh>
#include <aleph/persistenceDiagrams/Norms.hh>
#include <aleph/persistenceDiagrams/MultiScaleKernel.hh>
#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <limits>
#include <random>
#include <vector>

#include <cmath>

template <class T> aleph::PersistenceDiagram<T> createRandomPersistenceDiagram( unsigned n )
{
  std::random_device rd;
  std::default_random_engine rng( rd() );
  std::uniform_real_distribution<T> distribution( T(0), T( std::nextafter( T(1), std::numeric_limits<T>::max() ) ) );

  using PersistenceDiagram = aleph::PersistenceDiagram<T>;
  PersistenceDiagram D;

  for( unsigned i = 0; i < n; i++ )
  {
    auto x = distribution( rng );
    auto y = distribution( rng );

    if( x > y )
      std::swap( x,y );

    D.add( x,y );
  }

  return D;
}

template <class T> void testMultiScaleKernel()
{
  ALEPH_TEST_BEGIN( "Multi-scale kernel" );

  auto D1 = createRandomPersistenceDiagram<T>( 50 );
  auto D2 = createRandomPersistenceDiagram<T>( 50 );

  auto d1 = aleph::multiScalePseudoMetric( D1, D2, 1.0 );
  auto d2 = aleph::multiScalePseudoMetric( D1, D2, 2.0 );
  auto d3 = aleph::distances::wassersteinDistance( D1, D2, T(1) );

  // Non-negativity
  ALEPH_ASSERT_THROW( d1 > 0.0 );
  ALEPH_ASSERT_THROW( d2 > 0.0 );
  ALEPH_ASSERT_THROW( d3 > 0.0 );

  // Symmetry
  ALEPH_ASSERT_EQUAL( aleph::multiScalePseudoMetric(D1, D1, 1.0), aleph::multiScalePseudoMetric(D2, D2, 1.0) );
  ALEPH_ASSERT_EQUAL( aleph::multiScalePseudoMetric(D1, D1, 1.0), 0.0 );

  // Stability
  ALEPH_ASSERT_THROW( d1 < 1.0 / ( 1.0 / ( 1.0 * std::sqrt( 8.0 * M_PI ) ) * d3 ) );
  ALEPH_ASSERT_THROW( d2 < 1.0 / ( 1.0 / ( 2.0 * std::sqrt( 8.0 * M_PI ) ) * d3 ) );

  ALEPH_TEST_END();
}

template <class T> void testFrechetMean()
{
  using PersistenceDiagram = aleph::PersistenceDiagram<T>;

  ALEPH_TEST_BEGIN( "Persistence diagram mean");

  unsigned n = 10;

  std::vector<PersistenceDiagram> diagrams;
  diagrams.reserve( n );

  for( decltype(n) i = 0; i < n; i++ )
    diagrams.emplace_back( createRandomPersistenceDiagram<T>( 25 ) );

  auto D = aleph::mean( diagrams.begin(), diagrams.end() );
  auto P = aleph::totalPersistence( D );
  auto p = std::sqrt(25.0) * std::sqrt(0.50); // simple estimate of the mean value
                                              // for the total persistence

  ALEPH_ASSERT_THROW( D.size() > 0 );
  ALEPH_ASSERT_THROW( std::abs( P - p ) < 1.0 );

  ALEPH_TEST_END();
}

template <class T> void testWassersteinDistance()
{
  using Diagram = aleph::PersistenceDiagram<T>;
  using namespace aleph::distances;

  Diagram D1;
  D1.add( T(0.9), T(1.0) );
  D1.add( T(1.9), T(2.0) );
  D1.add( T(2.9), T(3.0) );
  D1.add( T(3.9), T(4.0) );

  {
    auto d11 = wassersteinDistance( D1, D1 );

    assert( d11 >= T() );
    assert( d11 == T() );

    ALEPH_ASSERT_THROW( d11 >= T() );
    ALEPH_ASSERT_THROW( d11 == T() );
  }

  Diagram D2;
  D2.add( T(0.9), T(1.0) );
  D2.add( T(1.9), T(2.0) );
  D2.add( T(2.9), T(3.0) );
  D2.add( T(3.9), T(9.9) );

  {
    auto d12 = wassersteinDistance( D1, D2 );
    auto d21 = wassersteinDistance( D2, D1 );

    ALEPH_ASSERT_THROW( d12 > T() );
    ALEPH_ASSERT_THROW( d21 > T() );

    ALEPH_ASSERT_THROW( d12 == d21 );
    ALEPH_ASSERT_THROW( std::abs( d12 -  T( 3.05 ) ) < 1e-8 );
  }
}

int main(int, char**)
{
  testFrechetMean<float> ();
  testFrechetMean<double>();

  testMultiScaleKernel<float> ();
  testMultiScaleKernel<double>();

  testWassersteinDistance<float> ();
  testWassersteinDistance<double>();
}
<commit_msg>Added test for nearest neighbour distance between persistence diagrams<commit_after>#include <tests/Base.hh>

#include <aleph/distances/NearestNeighbour.hh>
#include <aleph/distances/Wasserstein.hh>

#include <aleph/persistenceDiagrams/Mean.hh>
#include <aleph/persistenceDiagrams/Norms.hh>
#include <aleph/persistenceDiagrams/MultiScaleKernel.hh>
#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <limits>
#include <random>
#include <vector>

#include <cmath>

template <class T> aleph::PersistenceDiagram<T> createRandomPersistenceDiagram( unsigned n )
{
  std::random_device rd;
  std::default_random_engine rng( rd() );
  std::uniform_real_distribution<T> distribution( T(0), T( std::nextafter( T(1), std::numeric_limits<T>::max() ) ) );

  using PersistenceDiagram = aleph::PersistenceDiagram<T>;
  PersistenceDiagram D;

  for( unsigned i = 0; i < n; i++ )
  {
    auto x = distribution( rng );
    auto y = distribution( rng );

    if( x > y )
      std::swap( x,y );

    D.add( x,y );
  }

  return D;
}

template <class T> void testFrechetMean()
{
  using PersistenceDiagram = aleph::PersistenceDiagram<T>;

  ALEPH_TEST_BEGIN( "Persistence diagram mean");

  unsigned n = 10;

  std::vector<PersistenceDiagram> diagrams;
  diagrams.reserve( n );

  for( decltype(n) i = 0; i < n; i++ )
    diagrams.emplace_back( createRandomPersistenceDiagram<T>( 25 ) );

  auto D = aleph::mean( diagrams.begin(), diagrams.end() );
  auto P = aleph::totalPersistence( D );
  auto p = std::sqrt(25.0) * std::sqrt(0.50); // simple estimate of the mean value
                                              // for the total persistence

  ALEPH_ASSERT_THROW( D.size() > 0 );
  ALEPH_ASSERT_THROW( std::abs( P - p ) < 1.0 );

  ALEPH_TEST_END();
}

template <class T> void testMultiScaleKernel()
{
  ALEPH_TEST_BEGIN( "Multi-scale kernel" );

  auto D1 = createRandomPersistenceDiagram<T>( 50 );
  auto D2 = createRandomPersistenceDiagram<T>( 50 );

  auto d1 = aleph::multiScalePseudoMetric( D1, D2, 1.0 );
  auto d2 = aleph::multiScalePseudoMetric( D1, D2, 2.0 );
  auto d3 = aleph::distances::wassersteinDistance( D1, D2, T(1) );

  // Non-negativity
  ALEPH_ASSERT_THROW( d1 > 0.0 );
  ALEPH_ASSERT_THROW( d2 > 0.0 );
  ALEPH_ASSERT_THROW( d3 > 0.0 );

  // Symmetry
  ALEPH_ASSERT_EQUAL( aleph::multiScalePseudoMetric(D1, D1, 1.0), aleph::multiScalePseudoMetric(D2, D2, 1.0) );
  ALEPH_ASSERT_EQUAL( aleph::multiScalePseudoMetric(D1, D1, 1.0), 0.0 );

  // Stability
  ALEPH_ASSERT_THROW( d1 < 1.0 / ( 1.0 / ( 1.0 * std::sqrt( 8.0 * M_PI ) ) * d3 ) );
  ALEPH_ASSERT_THROW( d2 < 1.0 / ( 1.0 / ( 2.0 * std::sqrt( 8.0 * M_PI ) ) * d3 ) );

  ALEPH_TEST_END();
}

template <class T> void testNearestNeighbourDistance()
{
  ALEPH_TEST_BEGIN( "Nearest neighbour distance" );

  auto D1 = createRandomPersistenceDiagram<T>( 50 );
  auto D2 = createRandomPersistenceDiagram<T>( 50 );

  auto dNearestNeighbour = aleph::distances::nearestNeighbourDistance( D1, D2 );
  auto dWasserstein      = aleph::distances::wassersteinDistance( D1, D2, T(1) );

  ALEPH_ASSERT_THROW( dNearestNeighbour < dWasserstein );

  ALEPH_TEST_END();
}

template <class T> void testWassersteinDistance()
{
  using Diagram = aleph::PersistenceDiagram<T>;
  using namespace aleph::distances;

  Diagram D1;
  D1.add( T(0.9), T(1.0) );
  D1.add( T(1.9), T(2.0) );
  D1.add( T(2.9), T(3.0) );
  D1.add( T(3.9), T(4.0) );

  {
    auto d11 = wassersteinDistance( D1, D1 );

    assert( d11 >= T() );
    assert( d11 == T() );

    ALEPH_ASSERT_THROW( d11 >= T() );
    ALEPH_ASSERT_THROW( d11 == T() );
  }

  Diagram D2;
  D2.add( T(0.9), T(1.0) );
  D2.add( T(1.9), T(2.0) );
  D2.add( T(2.9), T(3.0) );
  D2.add( T(3.9), T(9.9) );

  {
    auto d12 = wassersteinDistance( D1, D2 );
    auto d21 = wassersteinDistance( D2, D1 );

    ALEPH_ASSERT_THROW( d12 > T() );
    ALEPH_ASSERT_THROW( d21 > T() );

    ALEPH_ASSERT_THROW( d12 == d21 );
    ALEPH_ASSERT_THROW( std::abs( d12 -  T( 3.05 ) ) < 1e-8 );
  }
}

int main(int, char**)
{
  testFrechetMean<float> ();
  testFrechetMean<double>();

  testMultiScaleKernel<float> ();
  testMultiScaleKernel<double>();

  testNearestNeighbourDistance<float> ();
  testNearestNeighbourDistance<double>();

  testWassersteinDistance<float> ();
  testWassersteinDistance<double>();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <list>
#include <map>
#include <algorithm>
#include <locale>
#include <getopt.h>
#include <stdlib.h>
#include <unordered_map>

#include "search.h"
#include "stats.h"
#include "seq.h"

void build_patterns(std::ifstream & kmers_f, std::vector <std::pair <std::string, Node::Type> > & patterns)
{
    std::string tmp;
    while (!kmers_f.eof()) {
        std::getline(kmers_f, tmp);
        std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper);
        if (!tmp.empty()) {
            size_t tab = tmp.find('\t');
            if (tab == std::string::npos) {
                patterns.push_back(std::make_pair(tmp, Node::Type::adapter));
            } else {
                patterns.push_back(std::make_pair(tmp.substr(0, tab), Node::Type::adapter));
            }
        }
    }
    kmers_f.close();
}

ReadType check_read(std::string const & read, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    if (errors) {
        return (ReadType)search_inexact(read, root, patterns, errors);
    } else {
        return (ReadType)search_any(read, root);
    }
}

void filter_single_reads(std::ifstream & reads_f, std::ofstream & bad_f,
                         Stats & stats, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    Seq read;
    int processed = 0;

    while (read.read_seq(reads_f)) {
        ReadType type = check_read(read.seq, root, patterns, errors);
        stats.update(type);
        if (type != ReadType::ok) {
            read.write_seq(bad_f);
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

void filter_paired_reads(std::ifstream & reads1_f, std::ifstream & reads2_f,
                         std::ofstream & bad1_f, std::ofstream & bad2_f,
                         std::ofstream & se1_f, std::ofstream & se2_f,
                         Stats & stats1, Stats & stats2,
                         Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns,
                         int errors)
{
    Seq read1;
    Seq read2;
    int processed = 0;

    while (read1.read_seq(reads1_f) && read2.read_seq(reads2_f)) {
        ReadType type1 = check_read(read1.seq, root, patterns, errors);
        ReadType type2 = check_read(read2.seq, root, patterns, errors);
        if (type1 == ReadType::ok && type2 == ReadType::ok) {

        } else {
            stats1.update(type1, false);
            stats2.update(type2, false);
            if (type1 == ReadType::ok) {
                read1.write_seq(se1_f);
                read2.write_seq(bad2_f);
            } else if (type2 == ReadType::ok) {
                read1.write_seq(bad1_f);
                read2.write_seq(se2_f);
            } else {
                read1.write_seq(bad1_f);
                read2.write_seq(bad2_f);
            }
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

std::string remove_extension(const std::string& filename) {
    size_t lastdot = filename.find_last_of(".");
    if (lastdot == std::string::npos) return filename;
    return filename.substr(0, lastdot);
}

std::string basename(std::string const & path)
{
    std::string res(path);
    size_t pos = res.find_last_of('/');
    if (pos != std::string::npos) {
        res.erase(0, pos);
    }
    res = remove_extension(res);
    return res;
}

void print_help()
{
    std::cout << "./extractor [-i raw_data.fastq | -1 raw_data1.fastq -2 raw_data2.fastq] -o output_dir --fragments fragments.dat -e errors" << std::endl;
}

int main(int argc, char ** argv)
{
    Node root('0');
    std::vector <std::pair<std::string, Node::Type> > patterns;

    std::string kmers, reads, out_dir;
    std::string reads1, reads2;
    char rez = 0;
    int errors = 0;
    const struct option long_options[] = {
        {"fragments",required_argument,NULL,'a'},
        {NULL,0,NULL,0}
    };

    while ((rez = getopt_long(argc, argv, "1:2:l:p:a:i:o:e:", long_options, NULL)) != -1) {
        switch (rez) {
        case 'a':
            kmers = optarg;
            break;
        case 'i':
            reads = optarg;
            break;
        case '1':
            reads1 = optarg;
            break;
        case '2':
            reads2 = optarg;
            break;
        case 'o':
            out_dir = optarg;
            break;
        case 'e':
            errors = std::atoi(optarg);
            break;
        case '?':
            print_help();
            return -1;
        }
    }

    if (errors < 0 || errors > 2) {
        std::cout << "possible errors count are 0, 1, 2" << std::endl;
        return -1;
    }

    if (kmers.empty() || out_dir.empty() || (
            reads.empty() &&
            (reads1.empty() || reads2.empty()))) {
        print_help();
        return -1;
    }

    std::ifstream kmers_f (kmers.c_str());
    if (!kmers_f.good()) {
        std::cout << "Cannot open kmers file" << std::endl;
        print_help();
        return -1;
    }

    std::cout << "Building patterns..." << std::endl;
    build_patterns(kmers_f, patterns);

    if (patterns.empty()) {
        std::cout << "patterns are empty" << std::endl;
        return -1;
    }

    std::cout << "Building trie..." << std::endl;
    build_trie(root, patterns, errors);
	add_failures(root);

    std::cout << "Iterate reads..." << std::endl;
    if (!reads.empty()) {
        std::string reads_base = basename(reads);
        std::ifstream reads_f (reads.c_str());
        std::ofstream bad_f((out_dir + "/" + reads_base + ".filtered.fastq").c_str(), std::ofstream::out);

        if (!reads_f.good()) {
            std::cout << "Cannot open reads file" << std::endl;
            print_help();
            return -1;
        }

        if (!bad_f.good()) {
            std::cout << "Cannot open output file" << std::endl;
            print_help();
            return -1;
        }

        Stats stats(reads);

        filter_single_reads(reads_f, bad_f, stats, &root, patterns, errors);

        std::cout << stats;

        bad_f.close();
        reads_f.close();
    } else {
        std::string reads1_base = basename(reads1);
        std::string reads2_base = basename(reads2);
        std::ifstream reads1_f(reads1.c_str());
        std::ifstream reads2_f(reads2.c_str());

        std::string file_name_se1 = out_dir + "/" + reads1_base + ".se.fastq";
        std::string file_name_se2 = out_dir + "/" + reads2_base + ".se.fastq";
        std::string file_name_bad1 = out_dir + "/" + reads1_base + ".filtered.fastq";
        std::string file_name_bad2 = out_dir + "/" + reads2_base + ".filtered.fastq";

        std::ofstream se1_f(file_name_se1.c_str(),
                            std::ofstream::out);
        std::ofstream se2_f(file_name_se2.c_str(),
                            std::ofstream::out);
        std::ofstream bad1_f(file_name_bad1.c_str(),
                            std::ofstream::out);
        std::ofstream bad2_f(file_name_bad2.c_str(),
                            std::ofstream::out);

        std::cout << "Created output files:" << std::endl;
        std::cout << "\t" << file_name_se1 << std::endl;
        std::cout << "\t" << file_name_se2 << std::endl;
        std::cout << "\t" << file_name_bad1 << std::endl;
        std::cout << "\t" << file_name_bad2 << std::endl;

        if (!reads1_f.good() || !reads2_f.good()) {
            std::cout << "reads file is bad" << std::endl;
            print_help();
            return -1;
        }

        if (!bad1_f.good() || !bad2_f.good() ||
                !se1_f.good() || !se2_f.good()) {
            std::cout << "out file is bad" << std::endl;
            print_help();
            return -1;
        }

        Stats stats1(reads1);
        Stats stats2(reads2);

        filter_paired_reads(reads1_f, reads2_f,
                            bad1_f, bad2_f, se1_f, se2_f,
                            stats1, stats2,
                            &root, patterns, errors);

        std::cout << stats1;
        std::cout << stats2;

        bad1_f.close();
        bad2_f.close();
        reads1_f.close();
        reads2_f.close();
    }
}
<commit_msg>Extract tool documented<commit_after>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <list>
#include <map>
#include <algorithm>
#include <locale>
#include <getopt.h>
#include <stdlib.h>
#include <unordered_map>

#include "search.h"
#include "stats.h"
#include "seq.h"

/*! \brief Read adapter patterns from an input stream
 *
 *  \param[in]  kmers_f     an input stream to read the patterns from
 *  \param[out] patterns    the vector to which the patterns are written
 */
void build_patterns(std::ifstream & kmers_f, std::vector <std::pair <std::string, Node::Type> > & patterns)
{
    std::string tmp;
    while (!kmers_f.eof()) {
        std::getline(kmers_f, tmp);
        std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper);
        if (!tmp.empty()) {
            size_t tab = tmp.find('\t');
            if (tab == std::string::npos) {
                patterns.push_back(std::make_pair(tmp, Node::Type::adapter));
            } else {
                patterns.push_back(std::make_pair(tmp.substr(0, tab), Node::Type::adapter));
            }
        }
    }
    kmers_f.close();
}

/*! \brief Check a read against patterns
 *
 *  \param[in]  read        a read sequence
 *  \param[in]  root        a root of the trie structure used for string matching
 *  \param[in]  patterns    a vector of patterns
 *  \param[in]  errors      the number of resolved mismatches between a read and a pattern
 *  \return                 the read type
 */
ReadType check_read(std::string const & read, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    if (errors) {
        return (ReadType)search_inexact(read, root, patterns, errors);
    } else {
        return (ReadType)search_any(read, root);
    }
}

/*! \brief Filter single-end reads by patterns
 *
 *  \param[in]  reads_f     an input stream of read sequences
 *  \param[out] bad_f       an output stream to write filtered out reads to
 *  \param[out] stats       statistics on processed reads
 *  \param[out] root        a root of the trie structure used to perform string matching
 *  \param[in]  patterns    a vector of patterns for read filtration
 *  \param[in]  errors      the number of resolved mismatches between a read and a pattern
 */
void filter_single_reads(std::ifstream & reads_f, std::ofstream & bad_f,
                         Stats & stats, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    Seq read;
    int processed = 0;

    while (read.read_seq(reads_f)) {
        ReadType type = check_read(read.seq, root, patterns, errors);
        stats.update(type);
        if (type != ReadType::ok) {
            read.write_seq(bad_f);
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

/*! \brief Filter paired-end reads by patterns
 *
 *  \param[in]  reads1_f    an input stream of paired-end read 1 sequences
 *  \param[in]  reads2_f    an input stream of paired-end read 2 sequences
 *  \param[out] bad1_f      an output stream to write filtered out paired-end read 1 sequences to
 *  \param[out] bad2_f      an output stream to write filtered out paired-end read 2 sequences to
 *  \param[out] se1_f       an output stream to write filtered first parts of paired-end reads
 *  \param[out] se2_f       an output stream to write filtered second parts of paired-end reads
 *  \param[out] stats1      statistics on first parts of processed reads
 *  \param[out] stats2      statistics on second parts of processed reads
 *  \param[in]  root        a root of the trie structure used to perform string matching
 *  \param[in]  patterns    a vector of patterns for read filtration
 *  \param[in]  errors      the number of resolved mismatches between a read and a pattern
 *
 *  \remark The streams \p se1_f (and \p se2_f) correspond to paired-end reads which second
 *  (or first) part was filtered but the other one was left.
 */
void filter_paired_reads(std::ifstream & reads1_f, std::ifstream & reads2_f,
                         std::ofstream & bad1_f, std::ofstream & bad2_f,
                         std::ofstream & se1_f, std::ofstream & se2_f,
                         Stats & stats1, Stats & stats2,
                         Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns,
                         int errors)
{
    Seq read1;
    Seq read2;
    int processed = 0;

    while (read1.read_seq(reads1_f) && read2.read_seq(reads2_f)) {
        ReadType type1 = check_read(read1.seq, root, patterns, errors);
        ReadType type2 = check_read(read2.seq, root, patterns, errors);
        if (type1 == ReadType::ok && type2 == ReadType::ok) {

        } else {
            stats1.update(type1, false);
            stats2.update(type2, false);
            if (type1 == ReadType::ok) {
                read1.write_seq(se1_f);
                read2.write_seq(bad2_f);
            } else if (type2 == ReadType::ok) {
                read1.write_seq(bad1_f);
                read2.write_seq(se2_f);
            } else {
                read1.write_seq(bad1_f);
                read2.write_seq(bad2_f);
            }
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

/*! \brief Remove an extension from a filename
 *
 *  \param[in]  filename    a name of a file
 *  \return                 the specified filename without its extension
 */
std::string remove_extension(const std::string& filename) {
    size_t lastdot = filename.find_last_of(".");
    if (lastdot == std::string::npos) return filename;
    return filename.substr(0, lastdot);
}

/*! \brief Get a filename from a path
 *
 *  \param[in]  path    a file path
 *  \return             a filename from the specified path
 */
std::string basename(std::string const & path)
{
    std::string res(path);
    size_t pos = res.find_last_of('/');
    if (pos != std::string::npos) {
        res.erase(0, pos);
    }
    res = remove_extension(res);
    return res;
}

/*! \brief Print program parameters */
void print_help()
{
    std::cout << "./extractor [-i raw_data.fastq | -1 raw_data1.fastq -2 raw_data2.fastq] -o output_dir --fragments fragments.dat -e errors" << std::endl;
}

/*! \brief The main function of the **extract** tool. */
int main(int argc, char ** argv)
{
    Node root('0');
    std::vector <std::pair<std::string, Node::Type> > patterns;

    std::string kmers, reads, out_dir;
    std::string reads1, reads2;
    char rez = 0;
    int errors = 0;
    const struct option long_options[] = {
        {"fragments",required_argument,NULL,'a'},
        {NULL,0,NULL,0}
    };

    while ((rez = getopt_long(argc, argv, "1:2:l:p:a:i:o:e:", long_options, NULL)) != -1) {
        switch (rez) {
        case 'a':
            kmers = optarg;
            break;
        case 'i':
            reads = optarg;
            break;
        case '1':
            reads1 = optarg;
            break;
        case '2':
            reads2 = optarg;
            break;
        case 'o':
            out_dir = optarg;
            break;
        case 'e':
            errors = std::atoi(optarg);
            break;
        case '?':
            print_help();
            return -1;
        }
    }

    if (errors < 0 || errors > 2) {
        std::cout << "possible errors count are 0, 1, 2" << std::endl;
        return -1;
    }

    if (kmers.empty() || out_dir.empty() || (
            reads.empty() &&
            (reads1.empty() || reads2.empty()))) {
        print_help();
        return -1;
    }

    std::ifstream kmers_f (kmers.c_str());
    if (!kmers_f.good()) {
        std::cout << "Cannot open kmers file" << std::endl;
        print_help();
        return -1;
    }

    std::cout << "Building patterns..." << std::endl;
    build_patterns(kmers_f, patterns);

    if (patterns.empty()) {
        std::cout << "patterns are empty" << std::endl;
        return -1;
    }

    std::cout << "Building trie..." << std::endl;
    build_trie(root, patterns, errors);
	add_failures(root);

    std::cout << "Iterate reads..." << std::endl;
    if (!reads.empty()) {
        std::string reads_base = basename(reads);
        std::ifstream reads_f (reads.c_str());
        std::ofstream bad_f((out_dir + "/" + reads_base + ".filtered.fastq").c_str(), std::ofstream::out);

        if (!reads_f.good()) {
            std::cout << "Cannot open reads file" << std::endl;
            print_help();
            return -1;
        }

        if (!bad_f.good()) {
            std::cout << "Cannot open output file" << std::endl;
            print_help();
            return -1;
        }

        Stats stats(reads);

        filter_single_reads(reads_f, bad_f, stats, &root, patterns, errors);

        std::cout << stats;

        bad_f.close();
        reads_f.close();
    } else {
        std::string reads1_base = basename(reads1);
        std::string reads2_base = basename(reads2);
        std::ifstream reads1_f(reads1.c_str());
        std::ifstream reads2_f(reads2.c_str());

        std::string file_name_se1 = out_dir + "/" + reads1_base + ".se.fastq";
        std::string file_name_se2 = out_dir + "/" + reads2_base + ".se.fastq";
        std::string file_name_bad1 = out_dir + "/" + reads1_base + ".filtered.fastq";
        std::string file_name_bad2 = out_dir + "/" + reads2_base + ".filtered.fastq";

        std::ofstream se1_f(file_name_se1.c_str(),
                            std::ofstream::out);
        std::ofstream se2_f(file_name_se2.c_str(),
                            std::ofstream::out);
        std::ofstream bad1_f(file_name_bad1.c_str(),
                            std::ofstream::out);
        std::ofstream bad2_f(file_name_bad2.c_str(),
                            std::ofstream::out);

        std::cout << "Created output files:" << std::endl;
        std::cout << "\t" << file_name_se1 << std::endl;
        std::cout << "\t" << file_name_se2 << std::endl;
        std::cout << "\t" << file_name_bad1 << std::endl;
        std::cout << "\t" << file_name_bad2 << std::endl;

        if (!reads1_f.good() || !reads2_f.good()) {
            std::cout << "reads file is bad" << std::endl;
            print_help();
            return -1;
        }

        if (!bad1_f.good() || !bad2_f.good() ||
                !se1_f.good() || !se2_f.good()) {
            std::cout << "out file is bad" << std::endl;
            print_help();
            return -1;
        }

        Stats stats1(reads1);
        Stats stats2(reads2);

        filter_paired_reads(reads1_f, reads2_f,
                            bad1_f, bad2_f, se1_f, se2_f,
                            stats1, stats2,
                            &root, patterns, errors);

        std::cout << stats1;
        std::cout << stats2;

        bad1_f.close();
        bad2_f.close();
        reads1_f.close();
        reads2_f.close();
    }
}
<|endoftext|>


<commit_before><commit_msg>coverity#706034 Unintended sign extension<commit_after><|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p);
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if (((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
				if (m_low_prio_io)
				{
					FILE_IO_PRIORITY_HINT_INFO priorityHint;
					priorityHint.PriorityHint = IoPriorityHintLow;
					result = SetFileInformationByHandle(e.file_ptr->native_handle(),
						FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint));
				}
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p, e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(std::string const& p)
	{
		mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p);
		if (i != m_files.end()) m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<commit_msg>fixed windows unit tests<commit_after>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p);
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if (((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
// file prio is supported on vista and up
#if _WIN32_WINNT >= 0x0600
				if (m_low_prio_io)
				{
					FILE_IO_PRIORITY_HINT_INFO priorityHint;
					priorityHint.PriorityHint = IoPriorityHintLow;
					result = SetFileInformationByHandle(e.file_ptr->native_handle(),
						FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint));
				}
#endif
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p, e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(std::string const& p)
	{
		mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p);
		if (i != m_files.end()) m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<|endoftext|>