<commit_before>#include <vector>

#include "caffe/layers/affinity_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template<typename Dtype>
void AffinityLossLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  CHECK_EQ(bottom[0]->count(1), bottom[1]->count(1))<< "Inputs must have the same dimension.";
  diff_.ReshapeLike(*bottom[0]);
}

template<typename Dtype>
void AffinityLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  int count = bottom[0]->count();
  Dtype sum = 0.0;
  Dtype gap = this->layer_param_.affinity_loss_param().gap() / 2.0;
  Dtype delta = this->layer_param_.affinity_loss_param().delta();
  Dtype penalty = this->layer_param_.affinity_loss_param().penalty();
  bool huber = this->layer_param_.affinity_loss_param().pseudohuber();
  Dtype ranklossm = this->layer_param_.affinity_loss_param().ranklossmult();

  Dtype delta2 = delta*delta;
  const Dtype *labels = bottom[1]->cpu_data();
  const Dtype *preds = bottom[0]->cpu_data();
  Dtype *d = diff_.mutable_cpu_data();

  for (unsigned i = 0; i < count; i++) {
    Dtype label = labels[i];
    Dtype pred = preds[i];
    Dtype diff = 0.0;
    if (label > 0) { //normal euclidean
      diff = pred - label;
      if (diff < 0) {
        diff = std::min(diff + gap, Dtype(0));
      } else {
        diff = std::max(diff - gap, Dtype(0));
      }
    } else if (label < 0 && pred > -label) { //hinge like
      diff = pred + label + penalty;
      diff = std::max(diff - gap, Dtype(0));

    } else { //ignore
      diff = 0;
    }

    d[i] = diff;

    if(huber) {
      //https://en.wikipedia.org/wiki/Huber_loss
      Dtype hval = diff/delta;
      sum += delta2*(sqrt(1+hval*hval) - 1.0);
    }
    else {
      sum += diff * diff;
    }

  }

  Dtype rankloss = 0;
  if(ranklossm > 0) {
    //compute a rank loss
    nranklosspairs = 0; //save for backwards
    int num = bottom[0]->num();
    for (unsigned i = 0; i < num; i++) {
      Dtype labeli = labels[i];
      for (unsigned j = i + 1; j < num; j++) {
          Dtype labelj = labels[j];
          //correctly rank good poses
          if( (labeli > 0 && labelj > 0) ||
              //and bad-good poses where the bad can't be better than good
              (labeli > 0 && labelj < 0 && labeli > -labelj) ||
              (labeli < 0 && labelj > 0 && labelj > -labeli)) {
            rankloss += compute_pair_loss(bottom, i, j, ranklossm);
            nranklosspairs++;
          }
        }
    }
    rankloss /= nranklosspairs;
  }

  Dtype loss = sum / bottom[0]->num() / Dtype(2) + rankloss;
  top[0]->mutable_cpu_data()[0] = loss;
}

template<typename Dtype>
void AffinityLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {

  bool huber = this->layer_param_.affinity_loss_param().pseudohuber();
  Dtype scale = this->layer_param_.affinity_loss_param().scale();
  Dtype delta = this->layer_param_.affinity_loss_param().delta();
  Dtype maxgrad = this->layer_param_.affinity_loss_param().maxgrad();
  Dtype ranklossm = this->layer_param_.affinity_loss_param().ranklossmult();
  const Dtype *labels = bottom[1]->cpu_data();

  for (int i = 0; i < 2; ++i) {
    if (propagate_down[i]) {
      const Dtype sign = (i == 0) ? 1 : -1;
      if(huber) {
        //x/(1+(x/delta)^2)
        const Dtype *diff = diff_.cpu_data();
        Dtype *out = bottom[i]->mutable_cpu_diff();
        Dtype mult = sign * scale * top[0]->cpu_diff()[0] / bottom[i]->num();
        for(unsigned j = 0, n = bottom[i]->count(); j < n; j++) {
          Dtype x = diff[j];
          Dtype val = x/delta;
          out[j] = mult * x/(1.0 + val*val);
        }
      } else {
        const Dtype sign = (i == 0) ? 1 : -1;
        const Dtype alpha = sign * scale * top[0]->cpu_diff()[0] / bottom[i]->num();
        caffe_cpu_axpby(bottom[i]->count(),              // count
            alpha,                              // alpha
            diff_.cpu_data(),                   // a
            Dtype(0),                           // beta
            bottom[i]->mutable_cpu_diff());  // b
      }
    }
  }

  if(ranklossm > 0) {
    //compute a rank loss
    int num = bottom[0]->num();
    for (unsigned i = 0; i < num; i++) {
      Dtype labeli = labels[i];
      for (unsigned j = i + 1; j < num; j++) {
          Dtype labelj = labels[j];
          //correctly rank good poses
          if( (labeli > 0 && labelj > 0) ||
              //and bad-good poses where the bad can't be better than good
              (labeli > 0 && labelj < 0 && labeli > -labelj) ||
              (labeli < 0 && labelj > 0 && labelj > -labeli)) {
              compute_pair_gradient(top, bottom, i, j, ranklossm);
          }
        }
    }
  }

  if(maxgrad > 0) {
      //cap the maximum value of the gradient
      for(unsigned i = 0, n = bottom[0]->num(); i < n; i++) {
          Dtype x = bottom[0]->cpu_diff()[i];
          Dtype sign = x < 0 ? -1 : 1;
          x = fabs(x);
          bottom[0]->mutable_cpu_diff()[i] = sign*maxgrad*x/(x+maxgrad);
      }
  }
  /*
  LOG(INFO) << "AFFGRADS";
   for(unsigned i = 0, n = bottom[0]->num(); i < n; i++) {
   LOG(INFO) << bottom[0]->cpu_diff()[i];
   }
   */
}

template<typename Dtype>
Dtype AffinityLossLayer<Dtype>::compute_pair_loss(
        const vector<Blob<Dtype>*>& bottom, unsigned i, unsigned j, Dtype mult) {
    //bottom[0] should be scores
    //bottom[1] should be labels
    //scores can have one or two value (in which case binary classification is assumed)
    const Dtype* bottom_data = bottom[0]->cpu_data();
    const Dtype* bottom_label = bottom[1]->cpu_data();
    int num = bottom[0]->num();
    int dim = bottom[0]->count() / bottom[0]->num();
    Dtype loss = 0;
    Dtype si = 0, sj = 0;

    CHECK_LT(i, num)<< "RankLoss: invalid index i";
    CHECK_LT(j, num)<< "RankLoss: invalid index j";

    if (dim == 1) {
        //single scores
        si = fabs(bottom_data[i]);
        sj = fabs(bottom_data[j]);
    } else {
        CHECK(false) << "RankLoss requires single score per example or binary class probabilities.";
    }

    Dtype Li = bottom_label[i];
    Dtype Lj = bottom_label[j];
    Dtype diff = si - sj;
    Dtype ediff = exp(diff);
    Dtype Pij =  1.0;
    if(std::isfinite(ediff))
        Pij = ediff / (1 + ediff);

    if (Li > Lj) {
        Pij = std::max(Pij, Dtype(kLOG_THRESHOLD));
        loss = -log(Pij);
    } else {
        Dtype val = 1-Pij;
        val = std::max(val, Dtype(kLOG_THRESHOLD));
        loss = -log(val);
    }
//LOG(INFO) << "RANKPAIRLOSS " << i <<","<<j<<" "<<loss<< " " << Pij << " " << ediff << " s: " << si << "," << sj << " L: " << Li << "," << Lj;
    return mult*loss;
}

template<typename Dtype>
void AffinityLossLayer<Dtype>::compute_pair_gradient(
        const vector<Blob<Dtype>*>& top, const vector<Blob<Dtype>*>& bottom,
        unsigned i, unsigned j, Dtype mult) {
    const Dtype* bottom_data = bottom[0]->cpu_data();
    const Dtype* bottom_label = bottom[1]->cpu_data();
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();

    int num = bottom[0]->num();
    int dim = bottom[0]->count() / bottom[0]->num();
    Dtype si = 0, sj = 0;

    CHECK_LT(i, num)<< "RankLoss: invalid index i";
    CHECK_LT(j, num)<< "RankLoss: invalid index j";

    if (dim == 1) {
        //single scores
        si = fabs(bottom_data[i]);
        sj = fabs(bottom_data[j]);
    } else {
        CHECK(false) << "RankLoss requires single score per example or binary class probabilities.";
    }

    Dtype Li = bottom_label[i];
    Dtype Lj = bottom_label[j];
    Dtype diff = si-sj;
    Dtype ediff = exp(diff);
    Dtype d = 0;
    if(std::isfinite(ediff))
        d = - 1.0 / (1.0+exp(diff));

    if(Li < Lj) {
        //reverse sign
        d = -d;
    }

    //scale by number of pairs, which is computed in forward
    CHECK_GT(nranklosspairs, 0) << "Invalid nranklosspairs";
    d /= nranklosspairs; //and also by batch size
    //also by total loss
    Dtype scale = top[0]->cpu_diff()[0];
    d *= scale*mult; //and mult

    if(dim == 1) {
        bottom_diff[i] += d;
        bottom_diff[j] += -d;
        //LOG(INFO) << "RANKLOSS1 " << i << " L:" << Li << " s:" << si << " "<< d << "\t" << j << " L:" << Lj << " s:" << sj << " " << -d << "\n";

    }
}
INSTANTIATE_CLASS(AffinityLossLayer);
REGISTER_LAYER_CLASS(AffinityLoss);

}  // namespace caffe
<commit_msg>checkpoint<commit_after>#include <vector>

#include "caffe/layers/affinity_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template<typename Dtype>
void AffinityLossLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  CHECK_EQ(bottom[0]->count(1), bottom[1]->count(1))<< "Inputs must have the same dimension.";
  diff_.ReshapeLike(*bottom[0]);
}

template<typename Dtype>
void AffinityLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  int count = bottom[0]->count();
  Dtype sum = 0.0;
  Dtype gap = this->layer_param_.affinity_loss_param().gap() / 2.0;
  Dtype delta = this->layer_param_.affinity_loss_param().delta();
  Dtype penalty = this->layer_param_.affinity_loss_param().penalty();
  bool huber = this->layer_param_.affinity_loss_param().pseudohuber();
  Dtype ranklossm = this->layer_param_.affinity_loss_param().ranklossmult();

  Dtype delta2 = delta*delta;
  const Dtype *labels = bottom[1]->cpu_data();
  const Dtype *preds = bottom[0]->cpu_data();
  Dtype *d = diff_.mutable_cpu_data();

  for (unsigned i = 0; i < count; i++) {
    Dtype label = labels[i];
    Dtype pred = preds[i];
    Dtype diff = 0.0;
    if (label > 0) { //normal euclidean
      diff = pred - label;
      if (diff < 0) {
        diff = std::min(diff + gap, Dtype(0));
      } else {
        diff = std::max(diff - gap, Dtype(0));
      }
    } else if (label < 0 && pred > -label) { //hinge like
      diff = pred + label + penalty;
      diff = std::max(diff - gap, Dtype(0));

    } else { //ignore
      diff = 0;
    }

    d[i] = diff;

    if(huber) {
      //https://en.wikipedia.org/wiki/Huber_loss
      Dtype hval = diff/delta;
      sum += delta2*(sqrt(1+hval*hval) - 1.0);
    }
    else {
      sum += diff * diff;
    }

  }

  Dtype rankloss = 0;
  if(ranklossm > 0) {
    //compute a rank loss
    nranklosspairs = 0; //save for backwards
    int num = bottom[0]->num();
    for (unsigned i = 0; i < num; i++) {
      Dtype labeli = labels[i];
      for (unsigned j = i + 1; j < num; j++) {
          Dtype labelj = labels[j];
          //correctly rank good poses
          if( (labeli > 0 && labelj > 0) )//||
              //and bad-good poses where the bad can't be better than good
      //        (labeli > 0 && labelj < 0 && labeli > -labelj) ||
      //      (labeli < 0 && labelj > 0 && labelj > -labeli)) {
	  {
            rankloss += compute_pair_loss(bottom, i, j, ranklossm);
            nranklosspairs++;
          }
        }
    }
    rankloss /= nranklosspairs;
  }

  Dtype loss = sum / bottom[0]->num() / Dtype(2) + rankloss;
  top[0]->mutable_cpu_data()[0] = loss;
}

template<typename Dtype>
void AffinityLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {

  bool huber = this->layer_param_.affinity_loss_param().pseudohuber();
  Dtype scale = this->layer_param_.affinity_loss_param().scale();
  Dtype delta = this->layer_param_.affinity_loss_param().delta();
  Dtype maxgrad = this->layer_param_.affinity_loss_param().maxgrad();
  Dtype ranklossm = this->layer_param_.affinity_loss_param().ranklossmult();
  const Dtype *labels = bottom[1]->cpu_data();

  for (int i = 0; i < 2; ++i) {
    if (propagate_down[i]) {
      const Dtype sign = (i == 0) ? 1 : -1;
      if(huber) {
        //x/(1+(x/delta)^2)
        const Dtype *diff = diff_.cpu_data();
        Dtype *out = bottom[i]->mutable_cpu_diff();
        Dtype mult = sign * scale * top[0]->cpu_diff()[0] / bottom[i]->num();
        for(unsigned j = 0, n = bottom[i]->count(); j < n; j++) {
          Dtype x = diff[j];
          Dtype val = x/delta;
          out[j] = mult * x/(1.0 + val*val);
        }
      } else {
        const Dtype sign = (i == 0) ? 1 : -1;
        const Dtype alpha = sign * scale * top[0]->cpu_diff()[0] / bottom[i]->num();
        caffe_cpu_axpby(bottom[i]->count(),              // count
            alpha,                              // alpha
            diff_.cpu_data(),                   // a
            Dtype(0),                           // beta
            bottom[i]->mutable_cpu_diff());  // b
      }
    }
  }

  if(ranklossm > 0) {
    //compute a rank loss
    int num = bottom[0]->num();
    for (unsigned i = 0; i < num; i++) {
      Dtype labeli = labels[i];
      for (unsigned j = i + 1; j < num; j++) {
          Dtype labelj = labels[j];
          //correctly rank good poses
          if( (labeli > 0 && labelj > 0) )// ||
              //and bad-good poses where the bad can't be better than good
            //  (labeli > 0 && labelj < 0 && labeli > -labelj) ||
            // (labeli < 0 && labelj > 0 && labelj > -labeli)) {
	  {
              compute_pair_gradient(top, bottom, i, j, ranklossm);
          }
        }
    }
  }

  if(maxgrad > 0) {
      //cap the maximum value of the gradient
      for(unsigned i = 0, n = bottom[0]->num(); i < n; i++) {
          Dtype x = bottom[0]->cpu_diff()[i];
          Dtype sign = x < 0 ? -1 : 1;
          x = fabs(x);
          bottom[0]->mutable_cpu_diff()[i] = sign*maxgrad*x/(x+maxgrad);
      }
  }
 /*
   for(unsigned i = 0, n = bottom[0]->num(); i < n; i++) {
   LOG(INFO) << "AFFGRAD " << i << " " << bottom[0]->cpu_diff()[i];
   }
   */

}

template<typename Dtype>
Dtype AffinityLossLayer<Dtype>::compute_pair_loss(
        const vector<Blob<Dtype>*>& bottom, unsigned i, unsigned j, Dtype mult) {
    //bottom[0] should be scores
    //bottom[1] should be labels
    //scores can have one or two value (in which case binary classification is assumed)
    const Dtype* bottom_data = bottom[0]->cpu_data();
    const Dtype* bottom_label = bottom[1]->cpu_data();
    int num = bottom[0]->num();
    int dim = bottom[0]->count() / bottom[0]->num();
    Dtype loss = 0;
    Dtype si = 0, sj = 0;

    CHECK_LT(i, num)<< "RankLoss: invalid index i";
    CHECK_LT(j, num)<< "RankLoss: invalid index j";

    if (dim == 1) {
        //single scores
        si = bottom_data[i];
        sj = bottom_data[j];
    } else {
        CHECK(false) << "RankLoss requires single score per example or binary class probabilities.";
    }

    Dtype Li = bottom_label[i];
    Dtype Lj = bottom_label[j];
    Dtype diff = si - sj;
    Dtype ediff = exp(diff);
    Dtype Pij =  1.0;
    if(std::isfinite(ediff))
        Pij = ediff / (1 + ediff);

    if (Li > Lj) { //if one is negative, then should be less regardless
        Pij = std::max(Pij, Dtype(kLOG_THRESHOLD));
        loss = -log(Pij);
    } else {
        Dtype val = 1-Pij;
        val = std::max(val, Dtype(kLOG_THRESHOLD));
        loss = -log(val);
    }
//LOG(INFO) << "RANKPAIRLOSS " << i <<","<<j<<" "<<loss<< " " << Pij << " " << ediff << " s: " << si << "," << sj << " L: " << Li << "," << Lj;
    return mult*loss;
}

template<typename Dtype>
void AffinityLossLayer<Dtype>::compute_pair_gradient(
        const vector<Blob<Dtype>*>& top, const vector<Blob<Dtype>*>& bottom,
        unsigned i, unsigned j, Dtype mult) {
    const Dtype* bottom_data = bottom[0]->cpu_data();
    const Dtype* bottom_label = bottom[1]->cpu_data();
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();

    int num = bottom[0]->num();
    int dim = bottom[0]->count() / bottom[0]->num();
    Dtype si = 0, sj = 0;

    CHECK_LT(i, num)<< "RankLoss: invalid index i";
    CHECK_LT(j, num)<< "RankLoss: invalid index j";

    if (dim == 1) {
        //single scores
        si = bottom_data[i];
        sj = bottom_data[j];
    } else {
        CHECK(false) << "RankLoss requires single score per example or binary class probabilities.";
    }

    Dtype Li = bottom_label[i];
    Dtype Lj = bottom_label[j];
    Dtype diff = si-sj;
    Dtype ediff = exp(diff);
    Dtype d = 0;
    if(std::isfinite(ediff))
        d = - 1.0 / (1.0+exp(diff));

    if(Li < Lj) { //we only care about order, so okay if one is negative
        //reverse sign
        d = -d;
    }

    //scale by number of pairs, which is computed in forward
    CHECK_GT(nranklosspairs, 0) << "Invalid nranklosspairs";
    d /= nranklosspairs; //and also by batch size
    //also by total loss
    Dtype scale = top[0]->cpu_diff()[0];
    d *= scale*mult; //and mult

    if(dim == 1) {
        bottom_diff[i] += d;
        bottom_diff[j] += -d;
        //LOG(INFO) << "RANKLOSS1 " << i << " L:" << Li << " s:" << si << " "<< d << "\t" << j << " L:" << Lj << " s:" << sj << " " << -d << "\n";

    }
}
INSTANTIATE_CLASS(AffinityLossLayer);
REGISTER_LAYER_CLASS(AffinityLoss);

}  // namespace caffe
<|endoftext|>


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

    Copyright (C) 2005 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
                  2005 Frank Osterfeld <frank.osterfeld@kdemail.net>

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/
#include "storagemk4impl.h"
#include "feedstoragemk4impl.h"

#include <mk4.h>

#include <qmap.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtimer.h>

#include <kdebug.h>
#include <kstandarddirs.h>

namespace Akregator {
namespace Backend {

class StorageMK4Impl::StorageMK4ImplPrivate
{
    public:
        StorageMK4ImplPrivate() : modified(false),
            purl("url"),
            pFeedList("feedList"),
            pTagSet("tagSet"),
            punread("unread"),
            ptotalCount("totalCount"),
            plastFetch("lastFetch") {}

        c4_Storage* storage;
        c4_View archiveView;
        bool autoCommit;
        bool modified;
        QMap<QString, FeedStorage*> feeds;
        QStringList feedURLs;
        c4_StringProp purl, pFeedList, pTagSet;
        c4_IntProp punread, ptotalCount, plastFetch;
        QTimer* commitTimer;
        QString archivePath;

        c4_Storage* feedListStorage;
        c4_View feedListView;
};

void StorageMK4Impl::setArchivePath(const QString& archivePath)
{
    if (archivePath.isNull()) // if isNull, reset to default
        d->archivePath = defaultArchivePath();
    else
        d->archivePath = archivePath;
}

QString StorageMK4Impl::archivePath() const
{
    return d->archivePath;
}

StorageMK4Impl::StorageMK4Impl() : d(new StorageMK4ImplPrivate)
{
    setArchivePath(QString::null); // set path to default
    // commit changes every 3 seconds
    d->commitTimer = new QTimer(this);
    connect(d->commitTimer, SIGNAL(timeout()), this, SLOT(slotCommit()));
    d->commitTimer->start(3000);
}

QString StorageMK4Impl::defaultArchivePath()
{
    return KGlobal::dirs()->saveLocation("data", "akregator")+"Archive";
}

StorageMK4Impl::~StorageMK4Impl()
{
    close();
    delete d;
    d = 0;
}
void StorageMK4Impl::initialize(const QStringList&) {}

bool StorageMK4Impl::open(bool autoCommit)
{
    QString filePath = d->archivePath +"/archiveindex.mk4";
    d->storage = new c4_Storage(filePath.local8Bit(), true);
    d->archiveView = d->storage->GetAs("archive[url:S,unread:I,totalCount:I,lastFetch:I]");
    c4_View hash = d->storage->GetAs("archiveHash[_H:I,_R:I]");
    d->archiveView = d->archiveView.Hash(hash, 1); // hash on url
    d->autoCommit = autoCommit;

    filePath = d->archivePath +"/feedlistbackup.mk4";
    d->feedListStorage = new c4_Storage(filePath.local8Bit(), true);
    d->feedListView = d->feedListStorage->GetAs("archive[feedList:S,tagSet:S]");
    d->feedListView = d->feedListView.Hash(hash, 1); // hash on url
    return true;
}

bool StorageMK4Impl::autoCommit() const
{
    return d->autoCommit;
}

bool StorageMK4Impl::close()
{
    d->commitTimer->stop();

    QMap<QString, FeedStorage*>::Iterator it;
    QMap<QString, FeedStorage*>::Iterator end(d->feeds.end() ) ;
    for (it = d->feeds.begin(); it != end; ++it)
    {
        it.data()->close();
        delete it.data();
    }
    if(d->autoCommit)
        d->storage->Commit();

    delete d->storage;
    d->storage = 0;

    d->feedListStorage->Commit();
    delete d->feedListStorage;
    d->feedListStorage = 0;

    return true;
}

bool StorageMK4Impl::commit()
{
    QMap<QString, FeedStorage*>::Iterator it;
    QMap<QString, FeedStorage*>::Iterator end(d->feeds.end() ) ;
    for ( it = d->feeds.begin(); it != end; ++it )
        it.data()->commit();

    if(d->storage)
    {
        d->storage->Commit();
        return true;
    }

    return false;
}

bool StorageMK4Impl::rollback()
{
    QMap<QString, FeedStorage*>::Iterator it;
    QMap<QString, FeedStorage*>::Iterator end(d->feeds.end() ) ;
    for ( it = d->feeds.begin(); it != end; ++it )
        it.data()->rollback();

    if(d->storage)
    {
        d->storage->Rollback();
        return true;
    }
    return false;
}

int StorageMK4Impl::unreadFor(const QString &url)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);

    return findidx != -1 ? d->punread(d->archiveView.GetAt(findidx)) : 0;
}

void StorageMK4Impl::setUnreadFor(const QString &url, int unread)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);
    if (findidx == -1)
        return;
    findrow = d->archiveView.GetAt(findidx);
    d->punread(findrow) = unread;
    d->archiveView.SetAt(findidx, findrow);
    d->modified = true;
}

int StorageMK4Impl::totalCountFor(const QString &url)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);

    return findidx != -1 ? d->ptotalCount(d->archiveView.GetAt(findidx)) : 0;
}

void StorageMK4Impl::setTotalCountFor(const QString &url, int total)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);
    if (findidx == -1)
        return;
    findrow = d->archiveView.GetAt(findidx);
    d->ptotalCount(findrow) = total;
    d->archiveView.SetAt(findidx, findrow);
    d->modified = true;
}

int StorageMK4Impl::lastFetchFor(const QString& url)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);

    return (findidx != -1 ? d->plastFetch(d->archiveView.GetAt(findidx)) : 0);
}

void StorageMK4Impl::setLastFetchFor(const QString& url, int lastFetch)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);
    if (findidx == -1)
        return;
    findrow = d->archiveView.GetAt(findidx);
    d->plastFetch(findrow) = lastFetch;
    d->archiveView.SetAt(findidx, findrow);
    d->modified = true;
}

void StorageMK4Impl::slotCommit()
{
    if (d->modified)
    	commit();
    d->modified = false;
}

FeedStorage* StorageMK4Impl::archiveFor(const QString& url)
{
    if (!d->feeds.contains(url))
    {
        FeedStorage* fs = new FeedStorageMK4Impl(url, this);
        d->feeds[url] = fs;
        c4_Row findrow;
        d->purl(findrow) = url.ascii();
        int findidx = d->archiveView.Find(findrow);
        if (findidx == -1)
        {
            d->punread(findrow) = 0;
	    d->ptotalCount(findrow) = 0;
	    d->plastFetch(findrow) = 0;
            d->archiveView.Add(findrow);
            d->modified = true;
        }
        fs->convertOldArchive();
    }
    return d->feeds[url];
}

QStringList StorageMK4Impl::feeds() const
{
    // TODO: cache list
    QStringList list;
    int size = d->archiveView.GetSize();
    for (int i = 0; i < size; i++)
        list += QString(d->purl(d->archiveView.GetAt(i)));
    // fill with urls
    return list;

}

void StorageMK4Impl::add(Storage* source)
{
    QStringList feeds = source->feeds();
    QStringList::ConstIterator end(feeds.end() ) ;

    for (QStringList::ConstIterator it = feeds.begin(); it != end; ++it)
    {
        FeedStorage* fa = archiveFor(*it);
        fa->add(source->archiveFor(*it));
    }
}

void StorageMK4Impl::clear()
{
   QStringList feeds;
    int size = d->archiveView.GetSize();
    for (int i = 0; i < size; i++)
        feeds += QString(d->purl(d->archiveView.GetAt(i)));
    QStringList::ConstIterator end(feeds.end() ) ;

    for (QStringList::ConstIterator it = feeds.begin(); it != end; ++it)
    {
        FeedStorage* fa = archiveFor(*it);
        fa->clear();
        fa->commit();
        // FIXME: delete file (should be 0 in size now)
    }
    d->storage->RemoveAll();

}

void StorageMK4Impl::storeFeedList(const QString& opmlStr)
{
    c4_Row row;

    if  (d->feedListView.GetSize() == 0)
        d->feedListView.Add(row);

    row = d->feedListView.GetAt(0);
    d->pFeedList(row) = opmlStr.utf8().data();
    d->feedListView.SetAt(0, row);
    d->modified = true;
}

QString StorageMK4Impl::restoreFeedList() const
{
    if  (d->feedListView.GetSize() == 0)
        return "";

    c4_Row row = d->feedListView.GetAt(0);
    return QString::fromUtf8(d->pFeedList(row));
}

void StorageMK4Impl::storeTagSet(const QString& xmlStr)
{
    c4_Row row;

    if  (d->feedListView.GetSize() == 0)
        d->feedListView.Add(row);

    row = d->feedListView.GetAt(0);
    d->pTagSet(row) = xmlStr.utf8().data();
    d->feedListView.SetAt(0, row);
    d->modified = true;
}

QString StorageMK4Impl::restoreTagSet() const
{
    if  (d->feedListView.GetSize() == 0)
        return "";

    c4_Row row = d->feedListView.GetAt(0);
    return QString::fromUtf8(d->pTagSet(row));
}

} // namespace Backend
} // namespace Akregator

#include "storagemk4impl.moc"
<commit_msg>forwardport changes in mk4plugin<commit_after>/*
    This file is part of Akregator.

    Copyright (C) 2005 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
                  2005 Frank Osterfeld <frank.osterfeld@kdemail.net>

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/
#include "storagemk4impl.h"
#include "feedstoragemk4impl.h"

#include <mk4.h>

#include <qmap.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtimer.h>

#include <kdebug.h>
#include <kstandarddirs.h>

namespace Akregator {
namespace Backend {

class StorageMK4Impl::StorageMK4ImplPrivate
{
    public:
        StorageMK4ImplPrivate() : modified(false),
            purl("url"),
            pFeedList("feedList"),
            pTagSet("tagSet"),
            punread("unread"),
            ptotalCount("totalCount"),
            plastFetch("lastFetch") {}

        c4_Storage* storage;
        c4_View archiveView;
        bool autoCommit;
        bool modified;
        QMap<QString, FeedStorage*> feeds;
        QStringList feedURLs;
        c4_StringProp purl, pFeedList, pTagSet;
        c4_IntProp punread, ptotalCount, plastFetch;
        QTimer* commitTimer;
        QString archivePath;

        c4_Storage* feedListStorage;
        c4_View feedListView;
};

void StorageMK4Impl::setArchivePath(const QString& archivePath)
{
    if (archivePath.isNull()) // if isNull, reset to default
        d->archivePath = defaultArchivePath();
    else
        d->archivePath = archivePath;
}

QString StorageMK4Impl::archivePath() const
{
    return d->archivePath;
}

StorageMK4Impl::StorageMK4Impl() : d(new StorageMK4ImplPrivate)
{
    setArchivePath(QString::null); // set path to default
    // commit changes every 3 seconds
    d->commitTimer = new QTimer(this);
    connect(d->commitTimer, SIGNAL(timeout()), this, SLOT(slotCommit()));
    d->commitTimer->start(3000);
}

QString StorageMK4Impl::defaultArchivePath()
{
    return KGlobal::dirs()->saveLocation("data", "akregator")+"Archive";
}

StorageMK4Impl::~StorageMK4Impl()
{
    close();
    delete d;
    d = 0;
}
void StorageMK4Impl::initialize(const QStringList&) {}

bool StorageMK4Impl::open(bool autoCommit)
{
    QString filePath = d->archivePath +"/archiveindex.mk4";
    d->storage = new c4_Storage(filePath.local8Bit(), true);
    d->archiveView = d->storage->GetAs("archive[url:S,unread:I,totalCount:I,lastFetch:I]");
    c4_View hash = d->storage->GetAs("archiveHash[_H:I,_R:I]");
    d->archiveView = d->archiveView.Hash(hash, 1); // hash on url
    d->autoCommit = autoCommit;

    filePath = d->archivePath +"/feedlistbackup.mk4";
    d->feedListStorage = new c4_Storage(filePath.local8Bit(), true);
    d->feedListView = d->feedListStorage->GetAs("archive[feedList:S,tagSet:S]");
    return true;
}

bool StorageMK4Impl::autoCommit() const
{
    return d->autoCommit;
}

bool StorageMK4Impl::close()
{
    d->commitTimer->stop();

    QMap<QString, FeedStorage*>::Iterator it;
    QMap<QString, FeedStorage*>::Iterator end(d->feeds.end() ) ;
    for (it = d->feeds.begin(); it != end; ++it)
    {
        it.data()->close();
        delete it.data();
    }
    if(d->autoCommit)
        d->storage->Commit();

    delete d->storage;
    d->storage = 0;

    d->feedListStorage->Commit();
    delete d->feedListStorage;
    d->feedListStorage = 0;

    return true;
}

bool StorageMK4Impl::commit()
{
    QMap<QString, FeedStorage*>::Iterator it;
    QMap<QString, FeedStorage*>::Iterator end(d->feeds.end() ) ;
    for ( it = d->feeds.begin(); it != end; ++it )
        it.data()->commit();

    if(d->storage)
    {
        d->storage->Commit();
        return true;
    }

    return false;
}

bool StorageMK4Impl::rollback()
{
    QMap<QString, FeedStorage*>::Iterator it;
    QMap<QString, FeedStorage*>::Iterator end(d->feeds.end() ) ;
    for ( it = d->feeds.begin(); it != end; ++it )
        it.data()->rollback();

    if(d->storage)
    {
        d->storage->Rollback();
        return true;
    }
    return false;
}

int StorageMK4Impl::unreadFor(const QString &url)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);

    return findidx != -1 ? d->punread(d->archiveView.GetAt(findidx)) : 0;
}

void StorageMK4Impl::setUnreadFor(const QString &url, int unread)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);
    if (findidx == -1)
        return;
    findrow = d->archiveView.GetAt(findidx);
    d->punread(findrow) = unread;
    d->archiveView.SetAt(findidx, findrow);
    d->modified = true;
}

int StorageMK4Impl::totalCountFor(const QString &url)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);

    return findidx != -1 ? d->ptotalCount(d->archiveView.GetAt(findidx)) : 0;
}

void StorageMK4Impl::setTotalCountFor(const QString &url, int total)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);
    if (findidx == -1)
        return;
    findrow = d->archiveView.GetAt(findidx);
    d->ptotalCount(findrow) = total;
    d->archiveView.SetAt(findidx, findrow);
    d->modified = true;
}

int StorageMK4Impl::lastFetchFor(const QString& url)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);

    return (findidx != -1 ? d->plastFetch(d->archiveView.GetAt(findidx)) : 0);
}

void StorageMK4Impl::setLastFetchFor(const QString& url, int lastFetch)
{
    c4_Row findrow;
    d->purl(findrow) = url.ascii();
    int findidx = d->archiveView.Find(findrow);
    if (findidx == -1)
        return;
    findrow = d->archiveView.GetAt(findidx);
    d->plastFetch(findrow) = lastFetch;
    d->archiveView.SetAt(findidx, findrow);
    d->modified = true;
}

void StorageMK4Impl::slotCommit()
{
    if (d->modified)
    	commit();
    d->modified = false;
}

FeedStorage* StorageMK4Impl::archiveFor(const QString& url)
{
    if (!d->feeds.contains(url))
    {
        FeedStorage* fs = new FeedStorageMK4Impl(url, this);
        d->feeds[url] = fs;
        c4_Row findrow;
        d->purl(findrow) = url.ascii();
        int findidx = d->archiveView.Find(findrow);
        if (findidx == -1)
        {
            d->punread(findrow) = 0;
	    d->ptotalCount(findrow) = 0;
	    d->plastFetch(findrow) = 0;
            d->archiveView.Add(findrow);
            d->modified = true;
        }
        fs->convertOldArchive();
    }
    return d->feeds[url];
}

QStringList StorageMK4Impl::feeds() const
{
    // TODO: cache list
    QStringList list;
    int size = d->archiveView.GetSize();
    for (int i = 0; i < size; i++)
        list += QString(d->purl(d->archiveView.GetAt(i)));
    // fill with urls
    return list;

}

void StorageMK4Impl::add(Storage* source)
{
    QStringList feeds = source->feeds();
    QStringList::ConstIterator end(feeds.end() ) ;

    for (QStringList::ConstIterator it = feeds.begin(); it != end; ++it)
    {
        FeedStorage* fa = archiveFor(*it);
        fa->add(source->archiveFor(*it));
    }
}

void StorageMK4Impl::clear()
{
   QStringList feeds;
    int size = d->archiveView.GetSize();
    for (int i = 0; i < size; i++)
        feeds += QString(d->purl(d->archiveView.GetAt(i)));
    QStringList::ConstIterator end(feeds.end() ) ;

    for (QStringList::ConstIterator it = feeds.begin(); it != end; ++it)
    {
        FeedStorage* fa = archiveFor(*it);
        fa->clear();
        fa->commit();
        // FIXME: delete file (should be 0 in size now)
    }
    d->storage->RemoveAll();

}

void StorageMK4Impl::storeFeedList(const QString& opmlStr)
{

    if  (d->feedListView.GetSize() == 0)
    {
        c4_Row row;
        d->pFeedList(row) = !opmlStr.isEmpty() ? opmlStr.utf8().data() : "";
        d->pTagSet(row) = "";
        d->feedListView.Add(row);
    }
    else
    {
        c4_Row row = d->feedListView.GetAt(0);
        d->pFeedList(row) = !opmlStr.isEmpty() ? opmlStr.utf8().data() : "";
        d->feedListView.SetAt(0, row);
    }
    d->modified = true;
}

QString StorageMK4Impl::restoreFeedList() const
{
    if  (d->feedListView.GetSize() == 0)
        return "";

    c4_Row row = d->feedListView.GetAt(0);
    return QString::fromUtf8(d->pFeedList(row));
}

void StorageMK4Impl::storeTagSet(const QString& xmlStr)
{

    if  (d->feedListView.GetSize() == 0)
    {
        c4_Row row;
        d->pTagSet(row) = !xmlStr.isEmpty() ? xmlStr.utf8().data() : "";
        d->pFeedList(row) = "";
        d->feedListView.Add(row);
    }
    else
    {
        c4_Row row = d->feedListView.GetAt(0);
        d->pTagSet(row) = !xmlStr.isEmpty() ? xmlStr.utf8().data() : "";
        d->feedListView.SetAt(0, row);
    }
    d->modified = true;
}

QString StorageMK4Impl::restoreTagSet() const
{
    if  (d->feedListView.GetSize() == 0)
        return "";

    c4_Row row = d->feedListView.GetAt(0);
    return QString::fromUtf8(d->pTagSet(row));
}

} // namespace Backend
} // namespace Akregator

#include "storagemk4impl.moc"
<|endoftext|>


<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//
// File: FloatSingle.cpp
//

#include <common.h>

#include "floatsingle.h"

#define IS_FLT_INFINITY(x)         (((*((INT32*)((void*)&x))) & 0x7FFFFFFF) == 0x7F800000)

// Windows x86 and Windows ARM don't define _isnanf() but they do define a generic macro isnan()
#if (defined(_TARGET_X86_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)) && !defined(FEATURE_PAL) && !defined(_isnanf)
#if defined(_TARGET_ARM64_)
#define _isnanf      _isnan
#else
#define _isnanf      isnan
#endif
#endif

#

// The default compilation mode is /fp:precise, which disables floating-point intrinsics. This
// default compilation mode has previously caused performance regressions in floating-point code.
// We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance
// and is really unlikely to cause any other code regressions.

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
///
///                         beginning of /fp:fast scope
///
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

#ifdef _MSC_VER
#pragma float_control(precise, off)
#endif

/*=====================================Abs=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Abs, float x)
    FCALL_CONTRACT;

    return (float)fabsf(x);
FCIMPLEND

/*=====================================Acos=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Acos, float x)
    FCALL_CONTRACT;

    return (float)acosf(x);
FCIMPLEND

/*=====================================Asin=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Asin, float x)
    FCALL_CONTRACT;

    return (float)asinf(x);
FCIMPLEND

/*=====================================Atan=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Atan, float x)
    FCALL_CONTRACT;

    return (float)atanf(x);
FCIMPLEND

/*=====================================Atan2====================================
**
==============================================================================*/
FCIMPL2(float, COMSingle::Atan2, float y, float x)
    FCALL_CONTRACT;

    // atan2f(+/-INFINITY, +/-INFINITY) produces +/-0.785398163f (x is +INFINITY) and
    // +/-2.35619449f (x is -INFINITY) instead of the expected value of NaN. We handle
    // that case here ourselves.
    if (IS_FLT_INFINITY(y) && IS_FLT_INFINITY(x)) {
        return (float)(y / x);
    }

    return (float)atan2f(y, x);
FCIMPLEND

/*====================================Ceil======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Ceil, float x)
    FCALL_CONTRACT;

    return (float)ceilf(x);
FCIMPLEND

/*=====================================Cos======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Cos, float x)
    FCALL_CONTRACT;

    return (float)cosf(x);
FCIMPLEND

/*=====================================Cosh=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Cosh, float x)
    FCALL_CONTRACT;

    return (float)coshf(x);
FCIMPLEND

/*=====================================Exp======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Exp, float x)
    FCALL_CONTRACT;

    return (float)expf(x);
FCIMPLEND

/*====================================Floor=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Floor, float x)
    FCALL_CONTRACT;

    return (float)floorf(x);
FCIMPLEND

/*=====================================Log======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Log, float x)
    FCALL_CONTRACT;

    return (float)logf(x);
FCIMPLEND

/*====================================Log10=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Log10, float x)
    FCALL_CONTRACT;

    return (float)log10f(x);
FCIMPLEND

/*=====================================ModF=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::ModF, float* iptr)
    FCALL_CONTRACT;

    return (float)modff(*iptr, iptr);
FCIMPLEND

/*=====================================Pow======================================
**
==============================================================================*/
FCIMPL2(float, COMSingle::Pow, float x, float y)
    FCALL_CONTRACT;

    // The CRT version of pow preserves the NaN payload of x over the NaN payload of y.

    if(_isnanf(y)) {
        return y; // IEEE 754-2008: NaN payload must be preserved
    }

    if(_isnanf(x)) {
        return x; // IEEE 754-2008: NaN payload must be preserved
    }

    // The CRT version of powf does not return NaN for powf(-1.0f, +/-INFINITY) and
    // instead returns +1.0f.

    if(IS_FLT_INFINITY(y) && (x == -1.0f)) {
        INT32 result = CLR_NAN_32;
        return (*((float*)((INT32*)&result)));
    }

    return (float)powf(x, y);
FCIMPLEND

/*====================================Round=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Round, float x)
    FCALL_CONTRACT;

    // If the number has no fractional part do nothing
    // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
    if (x == (float)((INT32)x)) {
        return x;
    }

    // We had a number that was equally close to 2 integers.
    // We need to return the even one.

    float tempVal = (x + 0.5f);
    float flrTempVal = floorf(tempVal);

    if ((flrTempVal == tempVal) && (fmodf(tempVal, 2.0f) != 0)) {
        flrTempVal -= 1.0f;
    }

    return _copysignf(flrTempVal, x);
FCIMPLEND

/*=====================================Sin======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Sin, float x)
    FCALL_CONTRACT;

    return (float)sinf(x);
FCIMPLEND

/*=====================================Sinh=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Sinh, float x)
    FCALL_CONTRACT;

    return (float)sinhf(x);
FCIMPLEND

/*=====================================Sqrt=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Sqrt, float x)
    FCALL_CONTRACT;

    return (float)sqrtf(x);
FCIMPLEND

/*=====================================Tan======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Tan, float x)
    FCALL_CONTRACT;

    return (float)tanf(x);
FCIMPLEND

/*=====================================Tanh=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Tanh, float x)
    FCALL_CONTRACT;

    return (float)tanhf(x);
FCIMPLEND

#ifdef _MSC_VER
#pragma float_control(precise, on )
#endif

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
///
///                         End of /fp:fast scope
///
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Fix arm32 build break<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//
// File: FloatSingle.cpp
//

#include <common.h>

#include "floatsingle.h"

#define IS_FLT_INFINITY(x)         (((*((INT32*)((void*)&x))) & 0x7FFFFFFF) == 0x7F800000)

// Windows x86 and Windows ARM don't define _isnanf() but they do define a generic macro isnan()
#if (defined(_TARGET_X86_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)) && !defined(FEATURE_PAL) && !defined(_isnanf)
#if defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
#define _isnanf      _isnan
#else
#define _isnanf      isnan
#endif
#endif

#

// The default compilation mode is /fp:precise, which disables floating-point intrinsics. This
// default compilation mode has previously caused performance regressions in floating-point code.
// We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance
// and is really unlikely to cause any other code regressions.

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
///
///                         beginning of /fp:fast scope
///
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

#ifdef _MSC_VER
#pragma float_control(precise, off)
#endif

/*=====================================Abs=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Abs, float x)
    FCALL_CONTRACT;

    return (float)fabsf(x);
FCIMPLEND

/*=====================================Acos=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Acos, float x)
    FCALL_CONTRACT;

    return (float)acosf(x);
FCIMPLEND

/*=====================================Asin=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Asin, float x)
    FCALL_CONTRACT;

    return (float)asinf(x);
FCIMPLEND

/*=====================================Atan=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Atan, float x)
    FCALL_CONTRACT;

    return (float)atanf(x);
FCIMPLEND

/*=====================================Atan2====================================
**
==============================================================================*/
FCIMPL2(float, COMSingle::Atan2, float y, float x)
    FCALL_CONTRACT;

    // atan2f(+/-INFINITY, +/-INFINITY) produces +/-0.785398163f (x is +INFINITY) and
    // +/-2.35619449f (x is -INFINITY) instead of the expected value of NaN. We handle
    // that case here ourselves.
    if (IS_FLT_INFINITY(y) && IS_FLT_INFINITY(x)) {
        return (float)(y / x);
    }

    return (float)atan2f(y, x);
FCIMPLEND

/*====================================Ceil======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Ceil, float x)
    FCALL_CONTRACT;

    return (float)ceilf(x);
FCIMPLEND

/*=====================================Cos======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Cos, float x)
    FCALL_CONTRACT;

    return (float)cosf(x);
FCIMPLEND

/*=====================================Cosh=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Cosh, float x)
    FCALL_CONTRACT;

    return (float)coshf(x);
FCIMPLEND

/*=====================================Exp======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Exp, float x)
    FCALL_CONTRACT;

    return (float)expf(x);
FCIMPLEND

/*====================================Floor=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Floor, float x)
    FCALL_CONTRACT;

    return (float)floorf(x);
FCIMPLEND

/*=====================================Log======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Log, float x)
    FCALL_CONTRACT;

    return (float)logf(x);
FCIMPLEND

/*====================================Log10=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Log10, float x)
    FCALL_CONTRACT;

    return (float)log10f(x);
FCIMPLEND

/*=====================================ModF=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::ModF, float* iptr)
    FCALL_CONTRACT;

    return (float)modff(*iptr, iptr);
FCIMPLEND

/*=====================================Pow======================================
**
==============================================================================*/
FCIMPL2(float, COMSingle::Pow, float x, float y)
    FCALL_CONTRACT;

    // The CRT version of pow preserves the NaN payload of x over the NaN payload of y.

    if(_isnanf(y)) {
        return y; // IEEE 754-2008: NaN payload must be preserved
    }

    if(_isnanf(x)) {
        return x; // IEEE 754-2008: NaN payload must be preserved
    }

    // The CRT version of powf does not return NaN for powf(-1.0f, +/-INFINITY) and
    // instead returns +1.0f.

    if(IS_FLT_INFINITY(y) && (x == -1.0f)) {
        INT32 result = CLR_NAN_32;
        return (*((float*)((INT32*)&result)));
    }

    return (float)powf(x, y);
FCIMPLEND

/*====================================Round=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Round, float x)
    FCALL_CONTRACT;

    // If the number has no fractional part do nothing
    // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
    if (x == (float)((INT32)x)) {
        return x;
    }

    // We had a number that was equally close to 2 integers.
    // We need to return the even one.

    float tempVal = (x + 0.5f);
    float flrTempVal = floorf(tempVal);

    if ((flrTempVal == tempVal) && (fmodf(tempVal, 2.0f) != 0)) {
        flrTempVal -= 1.0f;
    }

    return _copysignf(flrTempVal, x);
FCIMPLEND

/*=====================================Sin======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Sin, float x)
    FCALL_CONTRACT;

    return (float)sinf(x);
FCIMPLEND

/*=====================================Sinh=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Sinh, float x)
    FCALL_CONTRACT;

    return (float)sinhf(x);
FCIMPLEND

/*=====================================Sqrt=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Sqrt, float x)
    FCALL_CONTRACT;

    return (float)sqrtf(x);
FCIMPLEND

/*=====================================Tan======================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Tan, float x)
    FCALL_CONTRACT;

    return (float)tanf(x);
FCIMPLEND

/*=====================================Tanh=====================================
**
==============================================================================*/
FCIMPL1(float, COMSingle::Tanh, float x)
    FCALL_CONTRACT;

    return (float)tanhf(x);
FCIMPLEND

#ifdef _MSC_VER
#pragma float_control(precise, on )
#endif

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
///
///                         End of /fp:fast scope
///
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>// Copyright (c) 2007, Google Inc.
// 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 Google Inc. 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.

extern "C" { // needed to compile on Leopard
  #include <mach-o/nlist.h>
  #include <stdlib.h>
  #include <stdio.h>
}

#include "breakpad_nlist_64.h"
#include <dlfcn.h>
#include <mach/mach_vm.h>
#include <algorithm>
#include "client/mac/handler/dynamic_images.h"

namespace google_breakpad {

//==============================================================================
// Returns the size of the memory region containing |address| and the
// number of bytes from |address| to the end of the region.
// We potentially, will extend the size of the original
// region by the size of the following region if it's contiguous with the
// first in order to handle cases when we're reading strings and they
// straddle two vm regions.
//
static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task,
                                          const void* address,
                                          mach_vm_size_t *size_to_end) {
  mach_vm_address_t region_base = (mach_vm_address_t)address;
  mach_vm_size_t region_size;
  natural_t nesting_level = 0;
  vm_region_submap_info_64 submap_info;
  mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;

  // Get information about the vm region containing |address|
  vm_region_recurse_info_t region_info;
  region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);

  kern_return_t result =
    mach_vm_region_recurse(target_task,
                           &region_base,
                           &region_size,
                           &nesting_level,
                           region_info,
                           &info_count);

  if (result == KERN_SUCCESS) {
    // Get distance from |address| to the end of this region
    *size_to_end = region_base + region_size -(mach_vm_address_t)address;

    // If we want to handle strings as long as 4096 characters we may need
    // to check if there's a vm region immediately following the first one.
    // If so, we need to extend |*size_to_end| to go all the way to the end
    // of the second region.
    if (*size_to_end < 4096) {
      // Second region starts where the first one ends
      mach_vm_address_t region_base2 =
        (mach_vm_address_t)(region_base + region_size);
      mach_vm_size_t region_size2;

      // Get information about the following vm region
      result =
        mach_vm_region_recurse(target_task,
                               &region_base2,
                               &region_size2,
                               &nesting_level,
                               region_info,
                               &info_count);

      // Extend region_size to go all the way to the end of the 2nd region
      if (result == KERN_SUCCESS
          && region_base2 == region_base + region_size) {
        region_size += region_size2;
      }
    }

    *size_to_end = region_base + region_size -(mach_vm_address_t)address;
  } else {
    region_size = 0;
    *size_to_end = 0;
  }

  return region_size;
}

#define kMaxStringLength 8192
//==============================================================================
// Reads a NULL-terminated string from another task.
//
// Warning!  This will not read any strings longer than kMaxStringLength-1
//
static void* ReadTaskString(task_port_t target_task,
                            const void* address) {
  // The problem is we don't know how much to read until we know how long
  // the string is. And we don't know how long the string is, until we've read
  // the memory!  So, we'll try to read kMaxStringLength bytes
  // (or as many bytes as we can until we reach the end of the vm region).
  mach_vm_size_t size_to_end;
  GetMemoryRegionSize(target_task, address, &size_to_end);

  if (size_to_end > 0) {
    mach_vm_size_t size_to_read =
      size_to_end > kMaxStringLength ? kMaxStringLength : size_to_end;

    kern_return_t kr;
    return ReadTaskMemory(target_task, address, (size_t)size_to_read, &kr);
  }

  return NULL;
}

//==============================================================================
// Reads an address range from another task.  A block of memory is malloced
// and should be freed by the caller.
void* ReadTaskMemory(task_port_t target_task,
                     const void* address,
                     size_t length,
                     kern_return_t *kr) {
  void* result = NULL;
  int systemPageSize = getpagesize();

  // use the negative of the page size for the mask to find the page address
  mach_vm_address_t page_address =
      reinterpret_cast<mach_vm_address_t>(address) & (-systemPageSize);

  mach_vm_address_t last_page_address =
      (reinterpret_cast<mach_vm_address_t>(address) + length +
       (systemPageSize - 1)) & (-systemPageSize);

  mach_vm_size_t page_size = last_page_address - page_address;
  uint8_t* local_start;
  uint32_t local_length;

  kern_return_t r;

  r = mach_vm_read(target_task,
                   page_address,
                   page_size,
                   reinterpret_cast<vm_offset_t*>(&local_start),
                   &local_length);

  if (kr != NULL) {
    *kr = r;
  }

  if (r == KERN_SUCCESS) {
    result = malloc(length);
    if (result != NULL) {
      memcpy(result,
             &local_start[(mach_vm_address_t)address - page_address],
             length);
    }
    mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
  }

  return result;
}

#pragma mark -

//==============================================================================
// Initializes vmaddr_, vmsize_, and slide_
void DynamicImage::CalculateMemoryAndVersionInfo() {
  breakpad_mach_header *header = GetMachHeader();

  // unless we can process the header, ensure that calls to
  // IsValid() will return false
  vmaddr_ = 0;
  vmsize_ = 0;
  slide_ = 0;
  version_ = 0;

  bool foundTextSection = false;
  bool foundDylibIDCommand = false;

#if __LP64__
  if(header->magic != MH_MAGIC_64) {
    return;
  }
#else
  if(header->magic != MH_MAGIC) {
    return;
  }
#endif

#ifdef __LP64__
  const uint32_t segmentLoadCommand = LC_SEGMENT_64;
#else
  const uint32_t segmentLoadCommand = LC_SEGMENT;
#endif

  const struct load_command *cmd =
    reinterpret_cast<const struct load_command *>(header + 1);

  for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
    if (!foundTextSection) {
      if (cmd->cmd == segmentLoadCommand) {
        const breakpad_mach_segment_command *seg =
            reinterpret_cast<const breakpad_mach_segment_command *>(cmd);

        if (!strcmp(seg->segname, "__TEXT")) {
          vmaddr_ = seg->vmaddr;
          vmsize_ = seg->vmsize;
          slide_ = 0;

          if (seg->fileoff == 0  &&  seg->filesize != 0) {
            slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr;
          }
          foundTextSection = true;
        }
      }
    }

    if (!foundDylibIDCommand) {
      if (cmd->cmd == LC_ID_DYLIB) {
        const struct dylib_command *dc =
            reinterpret_cast<const struct dylib_command *>(cmd);

        version_ = dc->dylib.current_version;
        foundDylibIDCommand = true;
      }
    }

    if (foundDylibIDCommand && foundTextSection) {
      return;
    }

    cmd = reinterpret_cast<const struct load_command *>
      (reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
  }

}

void DynamicImage::Print() {
  const char *path = GetFilePath();
  if (!path) {
    path = "(unknown)";
  }
  printf("%p: %s\n", GetLoadAddress(), path);
  breakpad_mach_header *header = GetMachHeader();
  MachHeader(*header).Print();
  printf("vmaddr\t\t: %p\n", reinterpret_cast<void*>(GetVMAddr()));
  printf("vmsize\t\t: %llu\n", GetVMSize());
  printf("slide\t\t: %td\n", GetVMAddrSlide());
}

#pragma mark -

//==============================================================================
// Loads information about dynamically loaded code in the given task.
DynamicImages::DynamicImages(mach_port_t task)
  : task_(task), image_list_() {
  ReadImageInfoForTask();
}

void* DynamicImages::GetDyldAllImageInfosPointer() {
  const char *imageSymbolName = "_dyld_all_image_infos";
  const char *dyldPath = "/usr/lib/dyld";
#ifndef __LP64__
  struct nlist l[8];
  memset(l, 0, sizeof(l) );

  // First we lookup the address of the "_dyld_all_image_infos" struct
  // which lives in "dyld".  This structure contains information about all
  // of the loaded dynamic images.
  struct nlist &list = l[0];
  list.n_un.n_name = const_cast<char *>(imageSymbolName);
  nlist(dyldPath,&list);
  if(list.n_value) {
    return reinterpret_cast<void*>(list.n_value);
  }

  return NULL;
#else
  struct nlist_64 l[8];
  struct nlist_64 &list = l[0];

  memset(l, 0, sizeof(l) );

  const char *symbolNames[2] = { imageSymbolName, "\0" };

  int invalidEntriesCount = breakpad_nlist_64(dyldPath,&list,symbolNames);

  if(invalidEntriesCount != 0) {
    return NULL;
  }
  assert(list.n_value);
  return reinterpret_cast<void*>(list.n_value);
#endif

}
//==============================================================================
// This code was written using dyld_debug.c (from Darwin) as a guide.
void DynamicImages::ReadImageInfoForTask() {
  void *imageList = GetDyldAllImageInfosPointer();

  if (imageList) {
    kern_return_t kr;
    // Read the structure inside of dyld that contains information about
    // loaded images.  We're reading from the desired task's address space.

    // Here we make the assumption that dyld loaded at the same address in
    // the crashed process vs. this one.  This is an assumption made in
    // "dyld_debug.c" and is said to be nearly always valid.
    dyld_all_image_infos *dyldInfo = reinterpret_cast<dyld_all_image_infos*>
      (ReadTaskMemory(task_,
                      reinterpret_cast<void*>(imageList),
                      sizeof(dyld_all_image_infos), &kr));

    if (dyldInfo) {
      // number of loaded images
      int count = dyldInfo->infoArrayCount;

      // Read an array of dyld_image_info structures each containing
      // information about a loaded image.
      dyld_image_info *infoArray = reinterpret_cast<dyld_image_info*>
        (ReadTaskMemory(task_,
                        dyldInfo->infoArray,
                        count*sizeof(dyld_image_info), &kr));

      image_list_.reserve(count);

      for (int i = 0; i < count; ++i) {
        dyld_image_info &info = infoArray[i];

        // First read just the mach_header from the image in the task.
        breakpad_mach_header *header = reinterpret_cast<breakpad_mach_header*>
          (ReadTaskMemory(task_,
                          info.load_address_,
                          sizeof(breakpad_mach_header), &kr));

        if (!header)
          break;   // bail on this dynamic image

        // Now determine the total amount we really want to read based on the
        // size of the load commands.  We need the header plus all of the
        // load commands.
        size_t header_size =
            sizeof(breakpad_mach_header) + header->sizeofcmds;

        free(header);

        header = reinterpret_cast<breakpad_mach_header*>
          (ReadTaskMemory(task_, info.load_address_, header_size, &kr));

        // Read the file name from the task's memory space.
        char *file_path = NULL;
        if (info.file_path_) {
          // Although we're reading kMaxStringLength bytes, it's copied in the
          // the DynamicImage constructor below with the correct string length,
          // so it's not really wasting memory.
          file_path = reinterpret_cast<char*>
            (ReadTaskString(task_, info.file_path_));
        }

        // Create an object representing this image and add it to our list.
        DynamicImage *new_image;
        new_image = new DynamicImage(header,
                                     header_size,
                                     (breakpad_mach_header*)info.load_address_,
                                     file_path,
                                     info.file_mod_date_,
                                     task_);

        if (new_image->IsValid()) {
          image_list_.push_back(DynamicImageRef(new_image));
        } else {
          delete new_image;
        }

        if (file_path) {
          free(file_path);
        }
      }

      free(dyldInfo);
      free(infoArray);

      // sorts based on loading address
      sort(image_list_.begin(), image_list_.end() );
      // remove duplicates - this happens in certain strange cases
      // You can see it in DashboardClient when Google Gadgets plugin
      // is installed.  Apple's crash reporter log and gdb "info shared"
      // both show the same library multiple times at the same address

      vector<DynamicImageRef>::iterator it = unique(image_list_.begin(),
                                                    image_list_.end() );
      image_list_.erase(it, image_list_.end());
    }
  }
}

//==============================================================================
DynamicImage  *DynamicImages::GetExecutableImage() {
  int executable_index = GetExecutableImageIndex();

  if (executable_index >= 0) {
    return GetImage(executable_index);
  }

  return NULL;
}

//==============================================================================
// returns -1 if failure to find executable
int DynamicImages::GetExecutableImageIndex() {
  int image_count = GetImageCount();

  for (int i = 0; i < image_count; ++i) {
    DynamicImage  *image = GetImage(i);
    if (image->GetMachHeader()->filetype == MH_EXECUTE) {
      return i;
    }
  }

  return -1;
}

}  // namespace google_breakpad
<commit_msg>review: http://breakpad.appspot.com/139001<commit_after>// Copyright (c) 2007, Google Inc.
// 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 Google Inc. 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.

extern "C" { // needed to compile on Leopard
  #include <mach-o/nlist.h>
  #include <stdlib.h>
  #include <stdio.h>
}

#include "breakpad_nlist_64.h"
#include <assert.h>
#include <dlfcn.h>
#include <mach/mach_vm.h>
#include <algorithm>
#include "client/mac/handler/dynamic_images.h"

namespace google_breakpad {

//==============================================================================
// Returns the size of the memory region containing |address| and the
// number of bytes from |address| to the end of the region.
// We potentially, will extend the size of the original
// region by the size of the following region if it's contiguous with the
// first in order to handle cases when we're reading strings and they
// straddle two vm regions.
//
static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task,
                                          const void* address,
                                          mach_vm_size_t *size_to_end) {
  mach_vm_address_t region_base = (mach_vm_address_t)address;
  mach_vm_size_t region_size;
  natural_t nesting_level = 0;
  vm_region_submap_info_64 submap_info;
  mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;

  // Get information about the vm region containing |address|
  vm_region_recurse_info_t region_info;
  region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);

  kern_return_t result =
    mach_vm_region_recurse(target_task,
                           &region_base,
                           &region_size,
                           &nesting_level,
                           region_info,
                           &info_count);

  if (result == KERN_SUCCESS) {
    // Get distance from |address| to the end of this region
    *size_to_end = region_base + region_size -(mach_vm_address_t)address;

    // If we want to handle strings as long as 4096 characters we may need
    // to check if there's a vm region immediately following the first one.
    // If so, we need to extend |*size_to_end| to go all the way to the end
    // of the second region.
    if (*size_to_end < 4096) {
      // Second region starts where the first one ends
      mach_vm_address_t region_base2 =
        (mach_vm_address_t)(region_base + region_size);
      mach_vm_size_t region_size2;

      // Get information about the following vm region
      result =
        mach_vm_region_recurse(target_task,
                               &region_base2,
                               &region_size2,
                               &nesting_level,
                               region_info,
                               &info_count);

      // Extend region_size to go all the way to the end of the 2nd region
      if (result == KERN_SUCCESS
          && region_base2 == region_base + region_size) {
        region_size += region_size2;
      }
    }

    *size_to_end = region_base + region_size -(mach_vm_address_t)address;
  } else {
    region_size = 0;
    *size_to_end = 0;
  }

  return region_size;
}

#define kMaxStringLength 8192
//==============================================================================
// Reads a NULL-terminated string from another task.
//
// Warning!  This will not read any strings longer than kMaxStringLength-1
//
static void* ReadTaskString(task_port_t target_task,
                            const void* address) {
  // The problem is we don't know how much to read until we know how long
  // the string is. And we don't know how long the string is, until we've read
  // the memory!  So, we'll try to read kMaxStringLength bytes
  // (or as many bytes as we can until we reach the end of the vm region).
  mach_vm_size_t size_to_end;
  GetMemoryRegionSize(target_task, address, &size_to_end);

  if (size_to_end > 0) {
    mach_vm_size_t size_to_read =
      size_to_end > kMaxStringLength ? kMaxStringLength : size_to_end;

    kern_return_t kr;
    return ReadTaskMemory(target_task, address, (size_t)size_to_read, &kr);
  }

  return NULL;
}

//==============================================================================
// Reads an address range from another task.  A block of memory is malloced
// and should be freed by the caller.
void* ReadTaskMemory(task_port_t target_task,
                     const void* address,
                     size_t length,
                     kern_return_t *kr) {
  void* result = NULL;
  int systemPageSize = getpagesize();

  // use the negative of the page size for the mask to find the page address
  mach_vm_address_t page_address =
      reinterpret_cast<mach_vm_address_t>(address) & (-systemPageSize);

  mach_vm_address_t last_page_address =
      (reinterpret_cast<mach_vm_address_t>(address) + length +
       (systemPageSize - 1)) & (-systemPageSize);

  mach_vm_size_t page_size = last_page_address - page_address;
  uint8_t* local_start;
  uint32_t local_length;

  kern_return_t r;

  r = mach_vm_read(target_task,
                   page_address,
                   page_size,
                   reinterpret_cast<vm_offset_t*>(&local_start),
                   &local_length);

  if (kr != NULL) {
    *kr = r;
  }

  if (r == KERN_SUCCESS) {
    result = malloc(length);
    if (result != NULL) {
      memcpy(result,
             &local_start[(mach_vm_address_t)address - page_address],
             length);
    }
    mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
  }

  return result;
}

#pragma mark -

//==============================================================================
// Initializes vmaddr_, vmsize_, and slide_
void DynamicImage::CalculateMemoryAndVersionInfo() {
  breakpad_mach_header *header = GetMachHeader();

  // unless we can process the header, ensure that calls to
  // IsValid() will return false
  vmaddr_ = 0;
  vmsize_ = 0;
  slide_ = 0;
  version_ = 0;

  bool foundTextSection = false;
  bool foundDylibIDCommand = false;

#if __LP64__
  if(header->magic != MH_MAGIC_64) {
    return;
  }
#else
  if(header->magic != MH_MAGIC) {
    return;
  }
#endif

#ifdef __LP64__
  const uint32_t segmentLoadCommand = LC_SEGMENT_64;
#else
  const uint32_t segmentLoadCommand = LC_SEGMENT;
#endif

  const struct load_command *cmd =
    reinterpret_cast<const struct load_command *>(header + 1);

  for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
    if (!foundTextSection) {
      if (cmd->cmd == segmentLoadCommand) {
        const breakpad_mach_segment_command *seg =
            reinterpret_cast<const breakpad_mach_segment_command *>(cmd);

        if (!strcmp(seg->segname, "__TEXT")) {
          vmaddr_ = seg->vmaddr;
          vmsize_ = seg->vmsize;
          slide_ = 0;

          if (seg->fileoff == 0  &&  seg->filesize != 0) {
            slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr;
          }
          foundTextSection = true;
        }
      }
    }

    if (!foundDylibIDCommand) {
      if (cmd->cmd == LC_ID_DYLIB) {
        const struct dylib_command *dc =
            reinterpret_cast<const struct dylib_command *>(cmd);

        version_ = dc->dylib.current_version;
        foundDylibIDCommand = true;
      }
    }

    if (foundDylibIDCommand && foundTextSection) {
      return;
    }

    cmd = reinterpret_cast<const struct load_command *>
      (reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
  }

}

void DynamicImage::Print() {
  const char *path = GetFilePath();
  if (!path) {
    path = "(unknown)";
  }
  printf("%p: %s\n", GetLoadAddress(), path);
  breakpad_mach_header *header = GetMachHeader();
  MachHeader(*header).Print();
  printf("vmaddr\t\t: %p\n", reinterpret_cast<void*>(GetVMAddr()));
  printf("vmsize\t\t: %llu\n", GetVMSize());
  printf("slide\t\t: %td\n", GetVMAddrSlide());
}

#pragma mark -

//==============================================================================
// Loads information about dynamically loaded code in the given task.
DynamicImages::DynamicImages(mach_port_t task)
  : task_(task), image_list_() {
  ReadImageInfoForTask();
}

void* DynamicImages::GetDyldAllImageInfosPointer() {
  const char *imageSymbolName = "_dyld_all_image_infos";
  const char *dyldPath = "/usr/lib/dyld";
#ifndef __LP64__
  struct nlist l[8];
  memset(l, 0, sizeof(l) );

  // First we lookup the address of the "_dyld_all_image_infos" struct
  // which lives in "dyld".  This structure contains information about all
  // of the loaded dynamic images.
  struct nlist &list = l[0];
  list.n_un.n_name = const_cast<char *>(imageSymbolName);
  nlist(dyldPath,&list);
  if(list.n_value) {
    return reinterpret_cast<void*>(list.n_value);
  }

  return NULL;
#else
  struct nlist_64 l[8];
  struct nlist_64 &list = l[0];

  memset(l, 0, sizeof(l) );

  const char *symbolNames[2] = { imageSymbolName, "\0" };

  int invalidEntriesCount = breakpad_nlist_64(dyldPath,&list,symbolNames);

  if(invalidEntriesCount != 0) {
    return NULL;
  }
  assert(list.n_value);
  return reinterpret_cast<void*>(list.n_value);
#endif

}
//==============================================================================
// This code was written using dyld_debug.c (from Darwin) as a guide.
void DynamicImages::ReadImageInfoForTask() {
  void *imageList = GetDyldAllImageInfosPointer();

  if (imageList) {
    kern_return_t kr;
    // Read the structure inside of dyld that contains information about
    // loaded images.  We're reading from the desired task's address space.

    // Here we make the assumption that dyld loaded at the same address in
    // the crashed process vs. this one.  This is an assumption made in
    // "dyld_debug.c" and is said to be nearly always valid.
    dyld_all_image_infos *dyldInfo = reinterpret_cast<dyld_all_image_infos*>
      (ReadTaskMemory(task_,
                      reinterpret_cast<void*>(imageList),
                      sizeof(dyld_all_image_infos), &kr));

    if (dyldInfo) {
      // number of loaded images
      int count = dyldInfo->infoArrayCount;

      // Read an array of dyld_image_info structures each containing
      // information about a loaded image.
      dyld_image_info *infoArray = reinterpret_cast<dyld_image_info*>
        (ReadTaskMemory(task_,
                        dyldInfo->infoArray,
                        count*sizeof(dyld_image_info), &kr));

      image_list_.reserve(count);

      for (int i = 0; i < count; ++i) {
        dyld_image_info &info = infoArray[i];

        // First read just the mach_header from the image in the task.
        breakpad_mach_header *header = reinterpret_cast<breakpad_mach_header*>
          (ReadTaskMemory(task_,
                          info.load_address_,
                          sizeof(breakpad_mach_header), &kr));

        if (!header)
          break;   // bail on this dynamic image

        // Now determine the total amount we really want to read based on the
        // size of the load commands.  We need the header plus all of the
        // load commands.
        size_t header_size =
            sizeof(breakpad_mach_header) + header->sizeofcmds;

        free(header);

        header = reinterpret_cast<breakpad_mach_header*>
          (ReadTaskMemory(task_, info.load_address_, header_size, &kr));

        // Read the file name from the task's memory space.
        char *file_path = NULL;
        if (info.file_path_) {
          // Although we're reading kMaxStringLength bytes, it's copied in the
          // the DynamicImage constructor below with the correct string length,
          // so it's not really wasting memory.
          file_path = reinterpret_cast<char*>
            (ReadTaskString(task_, info.file_path_));
        }

        // Create an object representing this image and add it to our list.
        DynamicImage *new_image;
        new_image = new DynamicImage(header,
                                     header_size,
                                     (breakpad_mach_header*)info.load_address_,
                                     file_path,
                                     info.file_mod_date_,
                                     task_);

        if (new_image->IsValid()) {
          image_list_.push_back(DynamicImageRef(new_image));
        } else {
          delete new_image;
        }

        if (file_path) {
          free(file_path);
        }
      }

      free(dyldInfo);
      free(infoArray);

      // sorts based on loading address
      sort(image_list_.begin(), image_list_.end() );
      // remove duplicates - this happens in certain strange cases
      // You can see it in DashboardClient when Google Gadgets plugin
      // is installed.  Apple's crash reporter log and gdb "info shared"
      // both show the same library multiple times at the same address

      vector<DynamicImageRef>::iterator it = unique(image_list_.begin(),
                                                    image_list_.end() );
      image_list_.erase(it, image_list_.end());
    }
  }
}

//==============================================================================
DynamicImage  *DynamicImages::GetExecutableImage() {
  int executable_index = GetExecutableImageIndex();

  if (executable_index >= 0) {
    return GetImage(executable_index);
  }

  return NULL;
}

//==============================================================================
// returns -1 if failure to find executable
int DynamicImages::GetExecutableImageIndex() {
  int image_count = GetImageCount();

  for (int i = 0; i < image_count; ++i) {
    DynamicImage  *image = GetImage(i);
    if (image->GetMachHeader()->filetype == MH_EXECUTE) {
      return i;
    }
  }

  return -1;
}

}  // namespace google_breakpad
<|endoftext|>


<commit_before>// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

#ifndef MED_Utilities_HeaderFile
#define MED_Utilities_HeaderFile

#include "SMESH_DriverUNV.hxx"

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <stdexcept>
#include <cassert>
#include <cstdlib>

namespace UNV{
  using namespace std;

  const size_t theMaxLineLen = 82; // 80 for text + 2 for "\r\n"

  class MESHDRIVERUNV_EXPORT PrefixPrinter{
    static int myCounter;
  public:
    PrefixPrinter();
    ~PrefixPrinter();

    static string GetPrefix();
  };

  /**
   * @returns \p false when error occured, \p true otherwise.
   * Adjusts the \p in_stream to the beginning of the
   * dataset \p ds_name.
   */
  inline bool beginning_of_dataset(std::istream& in_file, const std::string& ds_name)
  {
    assert (in_file.good());
    assert (!ds_name.empty());

    std::string olds, news;

    in_file.seekg(0);
    while(true)
    {
      in_file >> olds >> news;
      /*
       * a "-1" followed by a number means the beginning of a dataset
       * stop combing at the end of the file
       */
      while( ((olds != "-1") || (news == "-1")))
      {
        olds = news;
        in_file >> news;

        if ( in_file.eof() || in_file.fail() )
        {
          in_file.clear();
          return false;
        }
      }
      if (news == ds_name)
        return true;
    }
    // should never end up here
    return false;
  }

  /**
   * Method for converting exponential notation
   * from "D" to "e", for example
   * \p 3.141592654D+00 \p --> \p 3.141592654e+00
   * in order to make it readable for C++.
   */
  inline double D_to_e(std::string& number)
  {
    /* find "D" in string, start looking at
     * 6th element, to improve speed.
     * We dont expect a "D" earlier
     */
    const int position = number.find("D",6);
    if(position != std::string::npos){
      number.replace(position, 1, "e");
    }
    return atof (number.c_str());
  }

  /**
   * @returns \p false when file is incorrect, \p true otherwise.
   * Check file with name \p theFileName for correct terminate
   * string, i.e. the next to the last line is equal to "    -1",
   */
  inline bool check_file(const std::string theFileName)
  {
    std::ifstream in_stream(theFileName.c_str());
    if (!in_stream)
      return false;
    std::string olds, news;
    while (!in_stream.eof()){
      olds = news;
      std::getline(in_stream, news, '\n');
    }
    return (olds == "    -1");
  }

  /*!
   * \brief reads a whole line
   *  \param in_stream - source stream
   *  \param next - if true, first reads the current line up to the end
   *  which is necessary after reading using >> operator
   *  \retval std::string - the result line
   */
  inline std::string read_line(std::ifstream& in_stream, const bool next=true)
  {
    std::string resLine;
    std::getline( in_stream, resLine );
    if ( next )
      std::getline( in_stream, resLine );

    if ( resLine.size() > 0 && resLine[ resLine.size()-1 ] == '\r' )
      resLine.resize( resLine.size()-1 );
    return resLine;
  }
};

#ifndef MESSAGE

#define MESSAGE(msg) std::cout<<__FILE__<<"["<<__LINE__<<"]::"<<msg<<endl;

#define BEGMSG(msg) std::cout<<UNV::PrefixPrinter::GetPrefix()<<msg

#define ADDMSG(msg) std::cout<<msg

#endif

#ifndef EXCEPTION

#define EXCEPTION(TYPE, MSG) {\
  std::ostringstream aStream;\
  aStream<<__FILE__<<"["<<__LINE__<<"]::"<<MSG;\
  throw TYPE(aStream.str());\
}

#endif

#endif
<commit_msg>Fix UNV file read which was broken due to missing cards<commit_after>// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

#ifndef MED_Utilities_HeaderFile
#define MED_Utilities_HeaderFile

#include "SMESH_DriverUNV.hxx"

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <stdexcept>
#include <cassert>
#include <cstdlib>

namespace UNV{
  using namespace std;

  const size_t theMaxLineLen = 82; // 80 for text + 2 for "\r\n"

  class MESHDRIVERUNV_EXPORT PrefixPrinter{
    static int myCounter;
  public:
    PrefixPrinter();
    ~PrefixPrinter();

    static string GetPrefix();
  };

  /**
   * @returns \p false when error occured, \p true otherwise.
   * Adjusts the \p in_stream to the beginning of the
   * dataset \p ds_name.
   */
  inline bool beginning_of_dataset(std::istream& in_file, const std::string& ds_name)
  {
    assert (in_file.good());
    assert (!ds_name.empty());

    std::string olds, news;

    in_file.seekg(0);
    while(!in_file.eof() && !in_file.fail())
    {
      in_file >> olds >> news;
      /*
       * a "-1" followed by a number means the beginning of a dataset
       * stop combing at the end of the file
       */
      while( ((olds != "-1") || (news == "-1")))
      {
        olds = news;
        in_file >> news;

        if ( in_file.eof() || in_file.fail() )
        {
          in_file.clear();
          return false;
        }
      }
      if (news == ds_name)
        return true;
    }
    // We didn't found the card
    // Let's rewind the file handler and return an error
    in_file.clear();
    return false;
  }

  /**
   * Method for converting exponential notation
   * from "D" to "e", for example
   * \p 3.141592654D+00 \p --> \p 3.141592654e+00
   * in order to make it readable for C++.
   */
  inline double D_to_e(std::string& number)
  {
    /* find "D" in string, start looking at
     * 6th element, to improve speed.
     * We dont expect a "D" earlier
     */
    const int position = number.find("D",6);
    if(position != std::string::npos){
      number.replace(position, 1, "e");
    }
    return atof (number.c_str());
  }

  /**
   * @returns \p false when file is incorrect, \p true otherwise.
   * Check file with name \p theFileName for correct terminate
   * string, i.e. the next to the last line is equal to "    -1",
   */
  inline bool check_file(const std::string theFileName)
  {
    std::ifstream in_stream(theFileName.c_str());
    if (!in_stream)
      return false;
    std::string olds, news;
    while (!in_stream.eof()){
      olds = news;
      std::getline(in_stream, news, '\n');
    }
    return (olds == "    -1");
  }

  /*!
   * \brief reads a whole line
   *  \param in_stream - source stream
   *  \param next - if true, first reads the current line up to the end
   *  which is necessary after reading using >> operator
   *  \retval std::string - the result line
   */
  inline std::string read_line(std::ifstream& in_stream, const bool next=true)
  {
    std::string resLine;
    std::getline( in_stream, resLine );
    if ( next )
      std::getline( in_stream, resLine );

    if ( resLine.size() > 0 && resLine[ resLine.size()-1 ] == '\r' )
      resLine.resize( resLine.size()-1 );
    return resLine;
  }
};

#ifndef MESSAGE

#define MESSAGE(msg) std::cout<<__FILE__<<"["<<__LINE__<<"]::"<<msg<<endl;

#define BEGMSG(msg) std::cout<<UNV::PrefixPrinter::GetPrefix()<<msg

#define ADDMSG(msg) std::cout<<msg

#endif

#ifndef EXCEPTION

#define EXCEPTION(TYPE, MSG) {\
  std::ostringstream aStream;\
  aStream<<__FILE__<<"["<<__LINE__<<"]::"<<MSG;\
  throw TYPE(aStream.str());\
}

#endif

#endif
<|endoftext|>