<commit_before>void AliTRDraw2digits()
{

  AliTRDrawData *raw = new AliTRDrawData();
  raw->SetDebug(3);
  raw->Raw2Digit();

  AliTRDdigitsManager *digitsManager = raw->GetDigitsManager();

  // The geometry object
  AliTRDgeometryFull *geo = new AliTRDgeometryFull();

  // The parameter object
  AliTRDparameter    *par = new AliTRDparameter("TRDparameter"
                                               ,"TRD parameter class");

  // Get the detector number
  Int_t iDet = 514;
  cout << " iDet = " << iDet << endl;

  // Define the detector matrix for one chamber
  const Int_t iSec = geo->GetSector(iDet);
  const Int_t iCha = geo->GetChamber(iDet);
  const Int_t iPla = geo->GetPlane(iDet);
  Int_t  rowMax = par->GetRowMax(iPla,iCha,iSec);
  Int_t  colMax = par->GetColMax(iPla);
  Int_t timeMax = par->GetTimeMax();
  cout << "Geometry: rowMax = "  <<  rowMax
                << " colMax = "  <<  colMax
                << " timeMax = " << timeMax << endl;
  AliTRDmatrix *matrix = new AliTRDmatrix(rowMax,colMax,timeMax,iSec,iCha,iPla);

  // Loop through the detector pixel
  for (Int_t time = 0; time < timeMax; time++) {
    for (Int_t  col = 0;  col <  colMax;  col++) {
      for (Int_t  row = 0;  row <  rowMax;  row++) {

        digit = digitsManager->GetDigit(row,col,time,iDet);

        matrix->SetSignal(row,col,time,digit->GetAmp());

        delete digit;

      }
    }
  }

  // Display the detector matrix
  matrix->Draw();
  matrix->ProjRow();
  matrix->ProjCol();
  matrix->ProjTime();

}

<commit_msg>Removing obsolete macro<commit_after><|endoftext|>


<commit_before>// Copyright 2004 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "re2/stringpiece.h"
#include "util/util.h"

using re2::StringPiece;

std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
  o.write(piece.data(), piece.size());
  return o;
}

bool StringPiece::_equal(const StringPiece& x, const StringPiece& y) {
  int len = x.size();
  if (len != y.size()) {
    return false;
  }
  const char* p = x.data();
  const char* p2 = y.data();
  // Test last byte in case strings share large common prefix
  if ((len > 0) && (p[len-1] != p2[len-1])) return false;
  const char* p_limit = p + len;
  for (; p < p_limit; p++, p2++) {
    if (*p != *p2)
      return false;
  }
  return true;
}

void StringPiece::CopyToString(string* target) const {
  target->assign(ptr_, length_);
}

int StringPiece::copy(char* buf, size_type n, size_type pos) const {
  int ret = min(length_ - pos, n);
  memcpy(buf, ptr_ + pos, ret);
  return ret;
}

bool StringPiece::contains(StringPiece s) const {
  return (size_t)find(s, 0) != npos;
}

int StringPiece::find(const StringPiece& s, size_type pos) const {
  if (length_ < 0 || pos > static_cast<size_type>(length_))
    return npos;

  const char* result = std::search(ptr_ + pos, ptr_ + length_,
                                   s.ptr_, s.ptr_ + s.length_);
  const size_type xpos = result - ptr_;
  return xpos + s.length_ <= static_cast<size_type>(length_) ? xpos : npos;
}

int StringPiece::find(char c, size_type pos) const {
  if (length_ <= 0 || pos >= static_cast<size_type>(length_)) {
    return npos;
  }
  const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
  return result != ptr_ + length_ ? result - ptr_ : npos;
}

int StringPiece::rfind(const StringPiece& s, size_type pos) const {
  if (length_ < s.length_) return npos;
  const size_t ulen = length_;
  if (s.length_ == 0) return min(ulen, pos);

  const char* last = ptr_ + min(ulen - s.length_, pos) + s.length_;
  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
  return result != last ? result - ptr_ : npos;
}

int StringPiece::rfind(char c, size_type pos) const {
  if (length_ <= 0) return npos;
  for (int i = min(pos, static_cast<size_type>(length_ - 1));
       i >= 0; --i) {
    if (ptr_[i] == c) {
      return i;
    }
  }
  return npos;
}

StringPiece StringPiece::substr(size_type pos, size_type n) const {
  if (pos > static_cast<size_type>(length_)) pos = static_cast<size_type>(length_);
  if (n > length_ - pos) n = length_ - pos;
  return StringPiece(ptr_ + pos, n);
}

const StringPiece::size_type StringPiece::npos = size_type(-1);
<commit_msg>Add the missing definition for StringPiece::AppendToString().<commit_after>// Copyright 2004 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "re2/stringpiece.h"
#include "util/util.h"

using re2::StringPiece;

std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
  o.write(piece.data(), piece.size());
  return o;
}

bool StringPiece::_equal(const StringPiece& x, const StringPiece& y) {
  int len = x.size();
  if (len != y.size()) {
    return false;
  }
  const char* p = x.data();
  const char* p2 = y.data();
  // Test last byte in case strings share large common prefix
  if ((len > 0) && (p[len-1] != p2[len-1])) return false;
  const char* p_limit = p + len;
  for (; p < p_limit; p++, p2++) {
    if (*p != *p2)
      return false;
  }
  return true;
}

void StringPiece::CopyToString(string* target) const {
  target->assign(ptr_, length_);
}

void StringPiece::AppendToString(string* target) const {
  target->append(ptr_, length_);
}

int StringPiece::copy(char* buf, size_type n, size_type pos) const {
  int ret = min(length_ - pos, n);
  memcpy(buf, ptr_ + pos, ret);
  return ret;
}

bool StringPiece::contains(StringPiece s) const {
  return (size_t)find(s, 0) != npos;
}

int StringPiece::find(const StringPiece& s, size_type pos) const {
  if (length_ < 0 || pos > static_cast<size_type>(length_))
    return npos;

  const char* result = std::search(ptr_ + pos, ptr_ + length_,
                                   s.ptr_, s.ptr_ + s.length_);
  const size_type xpos = result - ptr_;
  return xpos + s.length_ <= static_cast<size_type>(length_) ? xpos : npos;
}

int StringPiece::find(char c, size_type pos) const {
  if (length_ <= 0 || pos >= static_cast<size_type>(length_)) {
    return npos;
  }
  const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
  return result != ptr_ + length_ ? result - ptr_ : npos;
}

int StringPiece::rfind(const StringPiece& s, size_type pos) const {
  if (length_ < s.length_) return npos;
  const size_t ulen = length_;
  if (s.length_ == 0) return min(ulen, pos);

  const char* last = ptr_ + min(ulen - s.length_, pos) + s.length_;
  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
  return result != last ? result - ptr_ : npos;
}

int StringPiece::rfind(char c, size_type pos) const {
  if (length_ <= 0) return npos;
  for (int i = min(pos, static_cast<size_type>(length_ - 1));
       i >= 0; --i) {
    if (ptr_[i] == c) {
      return i;
    }
  }
  return npos;
}

StringPiece StringPiece::substr(size_type pos, size_type n) const {
  if (pos > static_cast<size_type>(length_)) pos = static_cast<size_type>(length_);
  if (n > length_ - pos) n = length_ - pos;
  return StringPiece(ptr_ + pos, n);
}

const StringPiece::size_type StringPiece::npos = size_type(-1);
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009-2010 Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "ScreenGraphicsItem.h"
#include "ScreenGraphicsItem_p.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleWidget.h"

// Qt
#include <QtGui/QMouseEvent>

using namespace Marble;

ScreenGraphicsItem::ScreenGraphicsItem( MarbleGraphicsItem *parent )
    : MarbleGraphicsItem( new ScreenGraphicsItemPrivate( this, parent ) )
{
}

ScreenGraphicsItem::ScreenGraphicsItem( ScreenGraphicsItemPrivate *d_ptr )
    : MarbleGraphicsItem( d_ptr )
{
}

ScreenGraphicsItem::~ScreenGraphicsItem()
{
}

QPointF ScreenGraphicsItem::position() const
{
    return p()->m_position;
}

void ScreenGraphicsItem::setPosition( const QPointF& position )
{
    p()->m_position = position;
}

QPointF ScreenGraphicsItem::positivePosition() const
{
    return p()->positivePosition();
}

QList<QPointF> ScreenGraphicsItem::absolutePositions() const
{
    return p()->absolutePositions();
}

ScreenGraphicsItem::GraphicsItemFlags ScreenGraphicsItem::flags() const
{
    return p()->m_flags;
}

void ScreenGraphicsItem::setFlags( ScreenGraphicsItem::GraphicsItemFlags flags )
{
    p()->m_flags = flags;
}

void ScreenGraphicsItem::changeViewport( ViewportParams *viewport )
{
    Q_UNUSED( viewport );
}

bool ScreenGraphicsItem::eventFilter( QObject *object, QEvent *e )
{
    MarbleWidget *widget = dynamic_cast<MarbleWidget*>(object);
    if ( !widget ) {
        return MarbleGraphicsItem::eventFilter( object, e );
    }

    if ( !p()->m_floatItemMoving ) {
        if ( MarbleGraphicsItem::eventFilter( object, e ) ) {
            return true;
        }

        if ( !visible() || !p()->isMovable() ) {
            return false;
        }

        if ( e->type() == QEvent::MouseMove ) {
            return false;
        }

        // Move ScreenGraphicsItem
        if ( e->type() == QEvent::MouseButtonPress )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>(e);

            // Click and move above a float item triggers moving the float item
            if ( contains( event->pos() ) ) {
                if ( event->button() == Qt::LeftButton ) {
                    p()->m_floatItemMoveStartPos = event->pos();
                    p()->m_floatItemMoving = true;
                    return true;
                }
            }
        }

        return false;
    }
    else {
        // Move ScreenGraphicsItem
        if ( e->type() == QEvent::MouseMove
            || e->type() == QEvent::MouseButtonPress
            || e->type() == QEvent::MouseButtonRelease )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>( e );
            // The rect the item was painted on before. We add one pixel as antialiasing could
            // result into painting on these pixels to.
            QRectF floatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                           size() + QSize( 2, 2 ) );

            if ( e->type() == QEvent::MouseMove && event->buttons() & Qt::LeftButton ) {
                if ( p()->m_floatItemMoving ) {
                    const QPoint &point = event->pos();
                    QPointF position = positivePosition();
                    qreal newX = qMax<qreal>( 0, position.x()+point.x()-p()->m_floatItemMoveStartPos.x() );
                    qreal newY = qMax<qreal>( 0, position.y()+point.y()-p()->m_floatItemMoveStartPos.y() );

                    // docking behavior
                    const qreal dockArea = 60.0; // Alignment area width/height
                    const qreal dockJump = 30.0; // Alignment indicator jump size
                    if ( widget->width()-size().width()-newX < dockArea ) {
                        newX = qMin( qreal( -1.0 ), size().width() + newX-widget->width() );
                        if ( p()->m_floatItemMoveStartPos.x() < event->pos().x() ) {
                            // Indicate change to right alignment with a short jump
                            newX = qMax( newX, -(dockArea-dockJump) );
                        }
                    }
                    if ( widget->height()-size().height()-newY < dockArea ) {
                        newY = qMin( qreal( -1.0 ), size().height() + newY-widget->height() );
                        if (p()->m_floatItemMoveStartPos.y()<event->pos().y()) {
                        // Indicate change to bottom alignment with a short jump
                        newY = qMax( newY, -( dockArea - dockJump ) );
                        }
                    }

                    setPosition( QPointF( newX,newY ) );
                    // The rect the item will be painted on now. We add one pixel as
                    // antialiasing could result into painting on these pixels to.
                    QRect newFloatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                                     size() + QSize( 2, 2 ) ).toRect();
                    p()->m_floatItemMoveStartPos = event->pos();
                    QRegion dirtyRegion( floatItemRect.toRect() );
                    dirtyRegion = dirtyRegion.united( newFloatItemRect );

                    widget->setAttribute( Qt::WA_NoSystemBackground,  false );
                    widget->update(dirtyRegion);
                    widget->setAttribute( Qt::WA_NoSystemBackground, widget->viewport()->mapCoversViewport() );
                    return true;
                }
            }

            if ( e->type() == QEvent::MouseButtonRelease ) {
                p()->m_floatItemMoving = false;
            }

            // Use a special cursor as long as the item is moved
            if ( p()->m_floatItemMoving ) {
                widget->setCursor(QCursor(Qt::SizeAllCursor));
                return true;
            }
        }

        return MarbleGraphicsItem::eventFilter( object, e );
    }
}

ScreenGraphicsItemPrivate *ScreenGraphicsItem::p() const
{
    return reinterpret_cast<ScreenGraphicsItemPrivate *>( d );
}
<commit_msg>remove redundant if-clause<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009-2010 Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "ScreenGraphicsItem.h"
#include "ScreenGraphicsItem_p.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleWidget.h"

// Qt
#include <QtGui/QMouseEvent>

using namespace Marble;

ScreenGraphicsItem::ScreenGraphicsItem( MarbleGraphicsItem *parent )
    : MarbleGraphicsItem( new ScreenGraphicsItemPrivate( this, parent ) )
{
}

ScreenGraphicsItem::ScreenGraphicsItem( ScreenGraphicsItemPrivate *d_ptr )
    : MarbleGraphicsItem( d_ptr )
{
}

ScreenGraphicsItem::~ScreenGraphicsItem()
{
}

QPointF ScreenGraphicsItem::position() const
{
    return p()->m_position;
}

void ScreenGraphicsItem::setPosition( const QPointF& position )
{
    p()->m_position = position;
}

QPointF ScreenGraphicsItem::positivePosition() const
{
    return p()->positivePosition();
}

QList<QPointF> ScreenGraphicsItem::absolutePositions() const
{
    return p()->absolutePositions();
}

ScreenGraphicsItem::GraphicsItemFlags ScreenGraphicsItem::flags() const
{
    return p()->m_flags;
}

void ScreenGraphicsItem::setFlags( ScreenGraphicsItem::GraphicsItemFlags flags )
{
    p()->m_flags = flags;
}

void ScreenGraphicsItem::changeViewport( ViewportParams *viewport )
{
    Q_UNUSED( viewport );
}

bool ScreenGraphicsItem::eventFilter( QObject *object, QEvent *e )
{
    MarbleWidget *widget = dynamic_cast<MarbleWidget*>(object);
    if ( !widget ) {
        return MarbleGraphicsItem::eventFilter( object, e );
    }

    if ( !p()->m_floatItemMoving ) {
        if ( MarbleGraphicsItem::eventFilter( object, e ) ) {
            return true;
        }

        if ( !visible() || !p()->isMovable() ) {
            return false;
        }

        if ( e->type() == QEvent::MouseMove ) {
            return false;
        }

        // Move ScreenGraphicsItem
        if ( e->type() == QEvent::MouseButtonPress )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>(e);

            // Click and move above a float item triggers moving the float item
            if ( contains( event->pos() ) ) {
                if ( event->button() == Qt::LeftButton ) {
                    p()->m_floatItemMoveStartPos = event->pos();
                    p()->m_floatItemMoving = true;
                    return true;
                }
            }
        }

        return false;
    }
    else {
        // Move ScreenGraphicsItem
        if ( e->type() == QEvent::MouseMove
            || e->type() == QEvent::MouseButtonPress
            || e->type() == QEvent::MouseButtonRelease )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>( e );
            // The rect the item was painted on before. We add one pixel as antialiasing could
            // result into painting on these pixels to.
            QRectF floatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                           size() + QSize( 2, 2 ) );

            if ( e->type() == QEvent::MouseMove && event->buttons() & Qt::LeftButton ) {
                    const QPoint &point = event->pos();
                    QPointF position = positivePosition();
                    qreal newX = qMax<qreal>( 0, position.x()+point.x()-p()->m_floatItemMoveStartPos.x() );
                    qreal newY = qMax<qreal>( 0, position.y()+point.y()-p()->m_floatItemMoveStartPos.y() );

                    // docking behavior
                    const qreal dockArea = 60.0; // Alignment area width/height
                    const qreal dockJump = 30.0; // Alignment indicator jump size
                    if ( widget->width()-size().width()-newX < dockArea ) {
                        newX = qMin( qreal( -1.0 ), size().width() + newX-widget->width() );
                        if ( p()->m_floatItemMoveStartPos.x() < event->pos().x() ) {
                            // Indicate change to right alignment with a short jump
                            newX = qMax( newX, -(dockArea-dockJump) );
                        }
                    }
                    if ( widget->height()-size().height()-newY < dockArea ) {
                        newY = qMin( qreal( -1.0 ), size().height() + newY-widget->height() );
                        if (p()->m_floatItemMoveStartPos.y()<event->pos().y()) {
                        // Indicate change to bottom alignment with a short jump
                        newY = qMax( newY, -( dockArea - dockJump ) );
                        }
                    }

                    setPosition( QPointF( newX,newY ) );
                    // The rect the item will be painted on now. We add one pixel as
                    // antialiasing could result into painting on these pixels to.
                    QRect newFloatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                                     size() + QSize( 2, 2 ) ).toRect();
                    p()->m_floatItemMoveStartPos = event->pos();
                    QRegion dirtyRegion( floatItemRect.toRect() );
                    dirtyRegion = dirtyRegion.united( newFloatItemRect );

                    widget->setAttribute( Qt::WA_NoSystemBackground,  false );
                    widget->update(dirtyRegion);
                    widget->setAttribute( Qt::WA_NoSystemBackground, widget->viewport()->mapCoversViewport() );
                    return true;
            }

            if ( e->type() == QEvent::MouseButtonRelease ) {
                p()->m_floatItemMoving = false;
            }

            // Use a special cursor as long as the item is moved
            if ( p()->m_floatItemMoving ) {
                widget->setCursor(QCursor(Qt::SizeAllCursor));
                return true;
            }
        }

        return MarbleGraphicsItem::eventFilter( object, e );
    }
}

ScreenGraphicsItemPrivate *ScreenGraphicsItem::p() const
{
    return reinterpret_cast<ScreenGraphicsItemPrivate *>( d );
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/prediction/predictor/vehicle/lane_sequence_predictor.h"

#include <cmath>
#include <utility>
#include <limits>
#include <memory>

#include "modules/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/adapters/proto/adapter_config.pb.h"
#include "modules/map/hdmap/hdmap_util.h"
#include "modules/prediction/common/road_graph.h"
#include "modules/prediction/common/prediction_gflags.h"
#include "modules/prediction/common/prediction_map.h"
#include "modules/prediction/container/container_manager.h"
#include "modules/prediction/container/obstacles/obstacles_container.h"
#include "modules/prediction/container/pose/pose_container.h"

namespace apollo {
namespace prediction {

using ::apollo::common::PathPoint;
using ::apollo::common::TrajectoryPoint;
using ::apollo::common::math::KalmanFilter;
using ::apollo::common::adapter::AdapterConfig;
using ::apollo::hdmap::LaneInfo;

void LaneSequencePredictor::Clear() {
  trajectories_.clear();
  adc_lane_id_.clear();
  adc_lane_s_ = 0.0;
}

void LaneSequencePredictor::Predict(Obstacle* obstacle) {
  Clear();

  CHECK_NOTNULL(obstacle);
  CHECK_GT(obstacle->history_size(), 0);

  const Feature& feature = obstacle->latest_feature();
  if (!feature.has_lane() || !feature.lane().has_lane_graph()) {
    AERROR << "Obstacle [" << obstacle->id() << " has no lane graph.";
    return;
  }

  std::string lane_id = "";
  if (feature.lane().has_lane_feature()) {
    lane_id = feature.lane().lane_feature().lane_id();
  }
  int num_lane_sequence = feature.lane().lane_graph().lane_sequence_size();
  std::vector<bool> enable_lane_sequence(num_lane_sequence, true);
  FilterLaneSequences(feature.lane().lane_graph(),
                      lane_id,
                      &enable_lane_sequence);

  for (int i = 0; i < num_lane_sequence; ++i) {
    const LaneSequence& sequence = feature.lane().lane_graph().lane_sequence(i);
    if (sequence.lane_segment_size() <= 0) {
      AERROR << "Empty lane segments.";
      continue;
    }

    if (!enable_lane_sequence[i]) {
      ADEBUG << "Lane sequence [" << ToString(sequence)
             << "] with probability ["
             <<sequence.probability() << "] is disqualified.";
      continue;
    }

    ADEBUG << "Obstacle [" << obstacle->id()
           << "] will draw a lane sequence trajectory ["
           << ToString(sequence) << "] with probability ["
           << sequence.probability() << "].";

    std::string curr_lane_id = sequence.lane_segment(0).lane_id();
    std::vector<TrajectoryPoint> points;
    DrawLaneSequenceTrajectoryPoints(
        obstacle->kf_lane_tracker(curr_lane_id), sequence,
        FLAGS_prediction_duration, FLAGS_prediction_freq, &points);

    Trajectory trajectory;
    GenerateTrajectory(points, &trajectory);
    trajectory.set_probability(sequence.probability());
    trajectories_.push_back(std::move(trajectory));
  }
  ADEBUG << "Obstacle [" << obstacle->id()
         << "] has total " << trajectories_.size()
         << " trajectories.";
}

void LaneSequencePredictor::FilterLaneSequences(
    const LaneGraph& lane_graph,
    const std::string& lane_id,
    std::vector<bool> *enable_lane_sequence) {
  int num_lane_sequence = lane_graph.lane_sequence_size();
  std::vector<int> lane_change_type(num_lane_sequence, -1);
  std::pair<int, double> change(-1, -1.0);
  std::pair<int, double> all(-1, -1.0);

  // Get ADC status
  GetADC();

  for (int i = 0; i < num_lane_sequence; ++i) {
    const LaneSequence& sequence = lane_graph.lane_sequence(i);

    // Get lane change type
    lane_change_type[i] = GetLaneChangeType(lane_id, sequence);

    double probability = sequence.probability();

    if (::apollo::common::math::DoubleCompare(probability, all.second) > 0 ||
        (::apollo::common::math::DoubleCompare(probability, all.second) == 0 &&
         lane_change_type[i] == 0)) {
      all.first = i;
      all.second = probability;
    }
    if (lane_change_type[i] > 0 &&
        ::apollo::common::math::DoubleCompare(probability, change.second) > 0) {
      change.first = i;
      change.second = probability;
    }
  }

  for (int i = 0; i < num_lane_sequence; ++i) {
    const LaneSequence& sequence = lane_graph.lane_sequence(i);

    // The obstacle has interference with ADC within a small distance
    if (::apollo::common::math::DoubleCompare(
        GetLaneChangeDistanceWithADC(sequence), FLAGS_lane_change_dist) < 0) {
      (*enable_lane_sequence)[i] = false;
      continue;
    }

    double probability = sequence.probability();
    if (::apollo::common::math::DoubleCompare(
        probability, FLAGS_lane_sequence_threshold) < 0 &&
        i != all.first) {
      (*enable_lane_sequence)[i] = false;
    } else if (change.first >= 0 &&
               change.first < num_lane_sequence &&
               lane_change_type[i] > 0 &&
               lane_change_type[i] != lane_change_type[change.first]) {
      (*enable_lane_sequence)[i] = false;
    }
  }
}

void LaneSequencePredictor::GetADC() {
  ObstaclesContainer *container = dynamic_cast<ObstaclesContainer*>(
      ContainerManager::instance()->GetContainer(
          AdapterConfig::PERCEPTION_OBSTACLES));
  if (container == nullptr) {
    AERROR << "Unavailable obstacle container";
    return;
  }

  Obstacle *adc = container->GetObstacle(PoseContainer::ID);
  if (adc != nullptr) {
    const Feature& feature = adc->latest_feature();
    if (feature.has_lane() &&
        feature.lane().has_lane_feature()) {
      adc_lane_id_ = feature.lane().lane_feature().lane_id();
      adc_lane_s_ = feature.lane().lane_feature().lane_s();
    }
    if (feature.has_position()) {
      adc_position_[0] = feature.position().x();
      adc_position_[1] = feature.position().y();
    }
  }
}

int LaneSequencePredictor::GetLaneChangeType(
    const std::string& lane_id,
    const LaneSequence& lane_sequence) {
  PredictionMap *map = PredictionMap::instance();

  std::string lane_change_id = lane_sequence.lane_segment(0).lane_id();
  if (lane_id == lane_change_id) {
    return 0;
  } else {
    if (map->IsLeftNeighborLane(
        map->LaneById(lane_change_id), map->LaneById(lane_id))) {
      return 1;
    } else if (map->IsRightNeighborLane(
        map->LaneById(lane_change_id), map->LaneById(lane_id))) {
      return 2;
    }
  }
  return -1;
}

double LaneSequencePredictor::GetLaneChangeDistanceWithADC(
    const LaneSequence& lane_sequence) {
  if (adc_lane_id_.empty() || lane_sequence.lane_segment_size() <= 0) {
    return std::numeric_limits<double>::max();
  }

  PredictionMap *map = PredictionMap::instance();
  std::string obstacle_lane_id = lane_sequence.lane_segment(0).lane_id();
  double obstacle_lane_s = lane_sequence.lane_segment(0).start_s();

  if (SameLaneSequence(obstacle_lane_id, obstacle_lane_s)) {
    return std::numeric_limits<double>::max();
  }

  double lane_s = 0.0;
  double lane_l = 0.0;
  if (map->GetProjection(adc_position_,
                         map->LaneById(obstacle_lane_id),
                         &lane_s, &lane_l)) {
    return std::fabs(lane_s - obstacle_lane_s);
  }
  return std::numeric_limits<double>::max();
}

bool LaneSequencePredictor::SameLaneSequence(
    const std::string& lane_id, double lane_s) {
  PredictionMap *map = PredictionMap::instance();

  std::shared_ptr<const LaneInfo> obstacle_lane = map->LaneById(lane_id);
  std::shared_ptr<const LaneInfo> adc_lane = map->LaneById(adc_lane_id_);

  if (obstacle_lane != nullptr && adc_lane != nullptr) {
    RoadGraph obstacle_road_graph(
        lane_s, FLAGS_lane_change_dist, obstacle_lane);
    LaneGraph obstacle_lane_graph;
    obstacle_road_graph.BuildLaneGraph(&obstacle_lane_graph);

    RoadGraph adc_road_graph(
        adc_lane_s_, FLAGS_lane_change_dist, adc_lane);
    LaneGraph adc_lane_graph;
    adc_road_graph.BuildLaneGraph(&adc_lane_graph);

    return obstacle_road_graph.IsOnLaneGraph(adc_lane, obstacle_lane_graph) ||
        adc_road_graph.IsOnLaneGraph(obstacle_lane, adc_lane_graph);
  }

  return false;
}

void LaneSequencePredictor::DrawLaneSequenceTrajectoryPoints(
    const KalmanFilter<double, 4, 2, 0>& kf,
    const LaneSequence& sequence,
    double total_time,
    double freq,
    std::vector<TrajectoryPoint> *points) {
  PredictionMap *map = PredictionMap::instance();

  Eigen::Matrix<double, 4, 1> state(kf.GetStateEstimate());
  double lane_s = state(0, 0);
  double lane_l = state(1, 0);
  double lane_speed = state(2, 0);
  double lane_acc = state(3, 0);

  Eigen::Matrix<double, 4, 4> transition(kf.GetTransitionMatrix());
  transition(0, 2) = freq;
  transition(0, 3) = 0.5 * freq * freq;
  transition(2, 3) = freq;

  int lane_segment_index = 0;
  std::string lane_id = sequence.lane_segment(lane_segment_index).lane_id();
  for (size_t i = 0; i < static_cast<size_t>(total_time / freq); ++i) {
    Eigen::Vector2d point;
    double theta = M_PI;
    if (!map->SmoothPointFromLane(lane_id, lane_s, lane_l, &point, &theta)) {
      AERROR << "Unable to get smooth point from lane [" << lane_id
             << "] with s [" << lane_s << "] and l [" << lane_l
             << "]";
      break;
    }

    if (points->size() > 0) {
      PathPoint *prev_point = points->back().mutable_path_point();
      double x_diff = point.x() - prev_point->x();
      double y_diff = point.y() - prev_point->y();
      if (::apollo::common::math::DoubleCompare(x_diff, 0.0) != 0 ||
          ::apollo::common::math::DoubleCompare(y_diff, 0.0) != 0) {
        theta = std::atan2(y_diff, x_diff);
        prev_point->set_theta(theta);
      } else {
        theta = prev_point->theta();
      }
    }

    // add trajectory point
    TrajectoryPoint trajectory_point;
    PathPoint path_point;
    path_point.set_x(point.x());
    path_point.set_y(point.y());
    path_point.set_z(0.0);
    path_point.set_theta(theta);
    trajectory_point.mutable_path_point()->CopyFrom(path_point);
    trajectory_point.set_v(lane_speed);
    trajectory_point.set_a(lane_acc);
    trajectory_point.set_relative_time(static_cast<double>(i) * freq);
    points->emplace_back(std::move(trajectory_point));

    // update state
    if (::apollo::common::math::DoubleCompare(lane_speed, 0.0) <= 0) {
      AWARN << "Non-positive lane_speed tacked : " << lane_speed;
      lane_speed = 0.0;
      lane_acc = 0.0;
      transition(1, 1) = 1.0;
    } else if (::apollo::common::math::DoubleCompare(
        lane_speed, FLAGS_max_speed) >= 0) {
      lane_speed = FLAGS_max_speed;
      lane_acc = 0.0;
    }
    state(2, 0) = lane_speed;
    state(3, 0) = lane_acc;

    state = transition * state;
    if (::apollo::common::math::DoubleCompare(lane_s, state(0, 0)) >= 0) {
      state(0, 0) = lane_s;
      state(1, 0) = lane_l;
      state(2, 0) = 0.0;
      state(3, 0) = 0.0;
      transition(1, 1) = 1.0;
    }
    lane_s = state(0, 0);
    lane_l = state(1, 0);
    lane_speed = state(2, 0);
    lane_acc = state(3, 0);

    // find next lane id
    while (lane_s > map->LaneById(lane_id)->total_length() &&
           lane_segment_index + 1 < sequence.lane_segment_size()) {
      lane_segment_index += 1;
      lane_s = lane_s - map->LaneById(lane_id)->total_length();
      state(0, 0) = lane_s;
      lane_id = sequence.lane_segment(lane_segment_index).lane_id();
    }
  }
}

std::string LaneSequencePredictor::ToString(const LaneSequence& sequence) {
  std::string str_lane_sequence = "";
  if (sequence.lane_segment_size() > 0) {
    str_lane_sequence += sequence.lane_segment(0).lane_id();
  }
  for (int i = 1; i < sequence.lane_segment_size(); ++i) {
    str_lane_sequence += ("->" + sequence.lane_segment(i).lane_id());
  }
  return str_lane_sequence;
}

}  // namespace prediction
}  // namespace apollo
<commit_msg>Prediction: small fix a log (#1344)<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/prediction/predictor/vehicle/lane_sequence_predictor.h"

#include <cmath>
#include <utility>
#include <limits>
#include <memory>

#include "modules/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/adapters/proto/adapter_config.pb.h"
#include "modules/map/hdmap/hdmap_util.h"
#include "modules/prediction/common/road_graph.h"
#include "modules/prediction/common/prediction_gflags.h"
#include "modules/prediction/common/prediction_map.h"
#include "modules/prediction/container/container_manager.h"
#include "modules/prediction/container/obstacles/obstacles_container.h"
#include "modules/prediction/container/pose/pose_container.h"

namespace apollo {
namespace prediction {

using ::apollo::common::PathPoint;
using ::apollo::common::TrajectoryPoint;
using ::apollo::common::math::KalmanFilter;
using ::apollo::common::adapter::AdapterConfig;
using ::apollo::hdmap::LaneInfo;

void LaneSequencePredictor::Clear() {
  trajectories_.clear();
  adc_lane_id_.clear();
  adc_lane_s_ = 0.0;
}

void LaneSequencePredictor::Predict(Obstacle* obstacle) {
  Clear();

  CHECK_NOTNULL(obstacle);
  CHECK_GT(obstacle->history_size(), 0);

  const Feature& feature = obstacle->latest_feature();
  if (!feature.has_lane() || !feature.lane().has_lane_graph()) {
    AERROR << "Obstacle [" << obstacle->id() << " has no lane graph.";
    return;
  }

  std::string lane_id = "";
  if (feature.lane().has_lane_feature()) {
    lane_id = feature.lane().lane_feature().lane_id();
  }
  int num_lane_sequence = feature.lane().lane_graph().lane_sequence_size();
  std::vector<bool> enable_lane_sequence(num_lane_sequence, true);
  FilterLaneSequences(feature.lane().lane_graph(),
                      lane_id,
                      &enable_lane_sequence);

  for (int i = 0; i < num_lane_sequence; ++i) {
    const LaneSequence& sequence = feature.lane().lane_graph().lane_sequence(i);
    if (sequence.lane_segment_size() <= 0) {
      AERROR << "Empty lane segments.";
      continue;
    }

    if (!enable_lane_sequence[i]) {
      ADEBUG << "Lane sequence [" << ToString(sequence)
             << "] with probability ["
             <<sequence.probability() << "] is disqualified.";
      continue;
    }

    ADEBUG << "Obstacle [" << obstacle->id()
           << "] will draw a lane sequence trajectory ["
           << ToString(sequence) << "] with probability ["
           << sequence.probability() << "].";

    std::string curr_lane_id = sequence.lane_segment(0).lane_id();
    std::vector<TrajectoryPoint> points;
    DrawLaneSequenceTrajectoryPoints(
        obstacle->kf_lane_tracker(curr_lane_id), sequence,
        FLAGS_prediction_duration, FLAGS_prediction_freq, &points);

    Trajectory trajectory;
    GenerateTrajectory(points, &trajectory);
    trajectory.set_probability(sequence.probability());
    trajectories_.push_back(std::move(trajectory));
  }
  ADEBUG << "Obstacle [" << obstacle->id()
         << "] has total " << trajectories_.size()
         << " trajectories.";
}

void LaneSequencePredictor::FilterLaneSequences(
    const LaneGraph& lane_graph,
    const std::string& lane_id,
    std::vector<bool> *enable_lane_sequence) {
  int num_lane_sequence = lane_graph.lane_sequence_size();
  std::vector<int> lane_change_type(num_lane_sequence, -1);
  std::pair<int, double> change(-1, -1.0);
  std::pair<int, double> all(-1, -1.0);

  // Get ADC status
  GetADC();

  for (int i = 0; i < num_lane_sequence; ++i) {
    const LaneSequence& sequence = lane_graph.lane_sequence(i);

    // Get lane change type
    lane_change_type[i] = GetLaneChangeType(lane_id, sequence);

    double probability = sequence.probability();

    if (::apollo::common::math::DoubleCompare(probability, all.second) > 0 ||
        (::apollo::common::math::DoubleCompare(probability, all.second) == 0 &&
         lane_change_type[i] == 0)) {
      all.first = i;
      all.second = probability;
    }
    if (lane_change_type[i] > 0 &&
        ::apollo::common::math::DoubleCompare(probability, change.second) > 0) {
      change.first = i;
      change.second = probability;
    }
  }

  for (int i = 0; i < num_lane_sequence; ++i) {
    const LaneSequence& sequence = lane_graph.lane_sequence(i);

    // The obstacle has interference with ADC within a small distance
    if (::apollo::common::math::DoubleCompare(
        GetLaneChangeDistanceWithADC(sequence), FLAGS_lane_change_dist) < 0) {
      (*enable_lane_sequence)[i] = false;
      continue;
    }

    double probability = sequence.probability();
    if (::apollo::common::math::DoubleCompare(
        probability, FLAGS_lane_sequence_threshold) < 0 &&
        i != all.first) {
      (*enable_lane_sequence)[i] = false;
    } else if (change.first >= 0 &&
               change.first < num_lane_sequence &&
               lane_change_type[i] > 0 &&
               lane_change_type[i] != lane_change_type[change.first]) {
      (*enable_lane_sequence)[i] = false;
    }
  }
}

void LaneSequencePredictor::GetADC() {
  ObstaclesContainer *container = dynamic_cast<ObstaclesContainer*>(
      ContainerManager::instance()->GetContainer(
          AdapterConfig::PERCEPTION_OBSTACLES));
  if (container == nullptr) {
    AERROR << "Unavailable obstacle container";
    return;
  }

  Obstacle *adc = container->GetObstacle(PoseContainer::ID);
  if (adc != nullptr) {
    const Feature& feature = adc->latest_feature();
    if (feature.has_lane() &&
        feature.lane().has_lane_feature()) {
      adc_lane_id_ = feature.lane().lane_feature().lane_id();
      adc_lane_s_ = feature.lane().lane_feature().lane_s();
    }
    if (feature.has_position()) {
      adc_position_[0] = feature.position().x();
      adc_position_[1] = feature.position().y();
    }
  }
}

int LaneSequencePredictor::GetLaneChangeType(
    const std::string& lane_id,
    const LaneSequence& lane_sequence) {
  PredictionMap *map = PredictionMap::instance();

  std::string lane_change_id = lane_sequence.lane_segment(0).lane_id();
  if (lane_id == lane_change_id) {
    return 0;
  } else {
    if (map->IsLeftNeighborLane(
        map->LaneById(lane_change_id), map->LaneById(lane_id))) {
      return 1;
    } else if (map->IsRightNeighborLane(
        map->LaneById(lane_change_id), map->LaneById(lane_id))) {
      return 2;
    }
  }
  return -1;
}

double LaneSequencePredictor::GetLaneChangeDistanceWithADC(
    const LaneSequence& lane_sequence) {
  if (adc_lane_id_.empty() || lane_sequence.lane_segment_size() <= 0) {
    return std::numeric_limits<double>::max();
  }

  PredictionMap *map = PredictionMap::instance();
  std::string obstacle_lane_id = lane_sequence.lane_segment(0).lane_id();
  double obstacle_lane_s = lane_sequence.lane_segment(0).start_s();

  if (SameLaneSequence(obstacle_lane_id, obstacle_lane_s)) {
    return std::numeric_limits<double>::max();
  }

  double lane_s = 0.0;
  double lane_l = 0.0;
  if (map->GetProjection(adc_position_,
                         map->LaneById(obstacle_lane_id),
                         &lane_s, &lane_l)) {
    return std::fabs(lane_s - obstacle_lane_s);
  }
  return std::numeric_limits<double>::max();
}

bool LaneSequencePredictor::SameLaneSequence(
    const std::string& lane_id, double lane_s) {
  PredictionMap *map = PredictionMap::instance();

  std::shared_ptr<const LaneInfo> obstacle_lane = map->LaneById(lane_id);
  std::shared_ptr<const LaneInfo> adc_lane = map->LaneById(adc_lane_id_);

  if (obstacle_lane != nullptr && adc_lane != nullptr) {
    RoadGraph obstacle_road_graph(
        lane_s, FLAGS_lane_change_dist, obstacle_lane);
    LaneGraph obstacle_lane_graph;
    obstacle_road_graph.BuildLaneGraph(&obstacle_lane_graph);

    RoadGraph adc_road_graph(
        adc_lane_s_, FLAGS_lane_change_dist, adc_lane);
    LaneGraph adc_lane_graph;
    adc_road_graph.BuildLaneGraph(&adc_lane_graph);

    return obstacle_road_graph.IsOnLaneGraph(adc_lane, obstacle_lane_graph) ||
        adc_road_graph.IsOnLaneGraph(obstacle_lane, adc_lane_graph);
  }

  return false;
}

void LaneSequencePredictor::DrawLaneSequenceTrajectoryPoints(
    const KalmanFilter<double, 4, 2, 0>& kf,
    const LaneSequence& sequence,
    double total_time,
    double freq,
    std::vector<TrajectoryPoint> *points) {
  PredictionMap *map = PredictionMap::instance();

  Eigen::Matrix<double, 4, 1> state(kf.GetStateEstimate());
  double lane_s = state(0, 0);
  double lane_l = state(1, 0);
  double lane_speed = state(2, 0);
  double lane_acc = state(3, 0);

  Eigen::Matrix<double, 4, 4> transition(kf.GetTransitionMatrix());
  transition(0, 2) = freq;
  transition(0, 3) = 0.5 * freq * freq;
  transition(2, 3) = freq;

  int lane_segment_index = 0;
  std::string lane_id = sequence.lane_segment(lane_segment_index).lane_id();
  for (size_t i = 0; i < static_cast<size_t>(total_time / freq); ++i) {
    Eigen::Vector2d point;
    double theta = M_PI;
    if (!map->SmoothPointFromLane(lane_id, lane_s, lane_l, &point, &theta)) {
      AERROR << "Unable to get smooth point from lane [" << lane_id
             << "] with s [" << lane_s << "] and l [" << lane_l
             << "]";
      break;
    }

    if (points->size() > 0) {
      PathPoint *prev_point = points->back().mutable_path_point();
      double x_diff = point.x() - prev_point->x();
      double y_diff = point.y() - prev_point->y();
      if (::apollo::common::math::DoubleCompare(x_diff, 0.0) != 0 ||
          ::apollo::common::math::DoubleCompare(y_diff, 0.0) != 0) {
        theta = std::atan2(y_diff, x_diff);
        prev_point->set_theta(theta);
      } else {
        theta = prev_point->theta();
      }
    }

    // add trajectory point
    TrajectoryPoint trajectory_point;
    PathPoint path_point;
    path_point.set_x(point.x());
    path_point.set_y(point.y());
    path_point.set_z(0.0);
    path_point.set_theta(theta);
    trajectory_point.mutable_path_point()->CopyFrom(path_point);
    trajectory_point.set_v(lane_speed);
    trajectory_point.set_a(lane_acc);
    trajectory_point.set_relative_time(static_cast<double>(i) * freq);
    points->emplace_back(std::move(trajectory_point));

    // update state
    if (::apollo::common::math::DoubleCompare(lane_speed, 0.0) <= 0) {
      ADEBUG << "Non-positive lane_speed tacked : " << lane_speed;
      lane_speed = 0.0;
      lane_acc = 0.0;
      transition(1, 1) = 1.0;
    } else if (::apollo::common::math::DoubleCompare(
        lane_speed, FLAGS_max_speed) >= 0) {
      lane_speed = FLAGS_max_speed;
      lane_acc = 0.0;
    }
    state(2, 0) = lane_speed;
    state(3, 0) = lane_acc;

    state = transition * state;
    if (::apollo::common::math::DoubleCompare(lane_s, state(0, 0)) >= 0) {
      state(0, 0) = lane_s;
      state(1, 0) = lane_l;
      state(2, 0) = 0.0;
      state(3, 0) = 0.0;
      transition(1, 1) = 1.0;
    }
    lane_s = state(0, 0);
    lane_l = state(1, 0);
    lane_speed = state(2, 0);
    lane_acc = state(3, 0);

    // find next lane id
    while (lane_s > map->LaneById(lane_id)->total_length() &&
           lane_segment_index + 1 < sequence.lane_segment_size()) {
      lane_segment_index += 1;
      lane_s = lane_s - map->LaneById(lane_id)->total_length();
      state(0, 0) = lane_s;
      lane_id = sequence.lane_segment(lane_segment_index).lane_id();
    }
  }
}

std::string LaneSequencePredictor::ToString(const LaneSequence& sequence) {
  std::string str_lane_sequence = "";
  if (sequence.lane_segment_size() > 0) {
    str_lane_sequence += sequence.lane_segment(0).lane_id();
  }
  for (int i = 1; i < sequence.lane_segment_size(); ++i) {
    str_lane_sequence += ("->" + sequence.lane_segment(i).lane_id());
  }
  return str_lane_sequence;
}

}  // namespace prediction
}  // namespace apollo
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009-2010 Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "ScreenGraphicsItem.h"
#include "ScreenGraphicsItem_p.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleWidget.h"

// Qt
#include <QtGui/QMouseEvent>

using namespace Marble;

ScreenGraphicsItem::ScreenGraphicsItem( MarbleGraphicsItem *parent )
    : MarbleGraphicsItem( new ScreenGraphicsItemPrivate( this, parent ) )
{
}

ScreenGraphicsItem::ScreenGraphicsItem( ScreenGraphicsItemPrivate *d_ptr )
    : MarbleGraphicsItem( d_ptr )
{
}

ScreenGraphicsItem::ScreenGraphicsItem( const QPointF& position, const QSizeF& size,
                                        ScreenGraphicsItemPrivate *d_ptr )
    : MarbleGraphicsItem( d_ptr )
{
    setPosition( position );
    setSize( size );
}

ScreenGraphicsItem::~ScreenGraphicsItem()
{
}

QPointF ScreenGraphicsItem::position() const
{
    return p()->m_position;
}

void ScreenGraphicsItem::setPosition( const QPointF& position )
{
    p()->m_position = position;
}

QPointF ScreenGraphicsItem::positivePosition() const
{
    return p()->positivePosition();
}

QList<QPointF> ScreenGraphicsItem::absolutePositions() const
{
    return p()->absolutePositions();
}

ScreenGraphicsItem::GraphicsItemFlags ScreenGraphicsItem::flags() const
{
    return p()->m_flags;
}

void ScreenGraphicsItem::setFlags( ScreenGraphicsItem::GraphicsItemFlags flags )
{
    p()->m_flags = flags;
}

void ScreenGraphicsItem::changeViewport( ViewportParams *viewport )
{
    Q_UNUSED( viewport );
}

bool ScreenGraphicsItem::eventFilter( QObject *object, QEvent *e )
{
    MarbleWidget *widget = dynamic_cast<MarbleWidget*>(object);
    if ( !widget ) {
        return MarbleGraphicsItem::eventFilter( object, e );
    }

    if ( !p()->m_floatItemMoving ) {
        if ( MarbleGraphicsItem::eventFilter( object, e ) ) {
            return true;
        }

        if ( !visible() || !p()->isMovable() ) {
            return false;
        }

        if ( e->type() == QEvent::MouseMove ) {
            return false;
        }

        // Move ScreenGraphicsItem
        if ( e->type() == QEvent::MouseButtonPress )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>(e);

            // Click and move above a float item triggers moving the float item
            if ( contains( event->pos() ) ) {
                if ( event->button() == Qt::LeftButton ) {
                    p()->m_floatItemMoveStartPos = event->pos();
                    p()->m_floatItemMoving = true;
                    return true;
                }
            }
        }

        return false;
    }
    else {
        // Move ScreenGraphicsItem
        bool cursorAboveFloatItem = false;
        if ( e->type() == QEvent::MouseMove
            || e->type() == QEvent::MouseButtonPress
            || e->type() == QEvent::MouseButtonRelease )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>( e );
            // The rect the item was painted on before. We add one pixel as antialiasing could
            // result into painting on these pixels to.
            QRectF floatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                           size() + QSize( 2, 2 ) );

            // Click and move above a float item triggers moving the float item
            if ( contains( event->pos() ) ) {
                cursorAboveFloatItem = true;

                if ( e->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton ) {
                    p()->m_floatItemMoveStartPos = event->pos();
                    return true;
                }
            }

            if ( e->type() == QEvent::MouseMove && event->buttons() & Qt::LeftButton )
            {
                p()->m_floatItemMoving = true;
                const QPoint &point = event->pos();
                QPointF position = positivePosition();
                qreal newX = position.x()+point.x()-p()->m_floatItemMoveStartPos.x();
                qreal newY = position.y()+point.y()-p()->m_floatItemMoveStartPos.y();
                if ( newX >= 0 && newY >= 0 ) {
                    // docking behavior
                    const qreal dockArea = 60.0; // Alignment area width/height
                    const qreal dockJump = 30.0; // Alignment indicator jump size
                    if ( widget->width()-size().width()-newX < dockArea ) {
                        newX = qMin( qreal( -1.0 ), size().width() + newX-widget->width() );
                        if ( p()->m_floatItemMoveStartPos.x() < event->pos().x() ) {
                            // Indicate change to right alignment with a short jump
                            newX = qMax( newX, -(dockArea-dockJump) );
                        }
                    }
                    if ( widget->height()-size().height()-newY < dockArea ) {
                        newY = qMin( qreal( -1.0 ), size().height() + newY-widget->height() );
                        if (p()->m_floatItemMoveStartPos.y()<event->pos().y()) {
                        // Indicate change to bottom alignment with a short jump
                        newY = qMax( newY, -( dockArea - dockJump ) );
                        }
                    }

                    setPosition( QPointF( newX,newY ) );
                    // The rect the item will be painted on now. We add one pixel as
                    // antialiasing could result into painting on these pixels to.
                    QRect newFloatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                                     size() + QSize( 2, 2 ) ).toRect();
                    p()->m_floatItemMoveStartPos = event->pos();
                    QRegion dirtyRegion( floatItemRect.toRect() );
                    dirtyRegion = dirtyRegion.united( newFloatItemRect );

                    widget->setAttribute( Qt::WA_NoSystemBackground,  false );
                    widget->repaint(dirtyRegion);
                    widget->setAttribute( Qt::WA_NoSystemBackground, widget->viewport()->mapCoversViewport() );
                    return true;
                }
            }

            if ( e->type() == QEvent::MouseButtonRelease ) {
                p()->m_floatItemMoving = false;
            }

            // Adjusting Cursor shape
            if ( cursorAboveFloatItem || p()->m_floatItemMoving ) {
                widget->setCursor(QCursor(Qt::SizeAllCursor));
                return true;
            }
        }

        return MarbleGraphicsItem::eventFilter( object, e );
    }
}

ScreenGraphicsItemPrivate *ScreenGraphicsItem::p() const
{
    return reinterpret_cast<ScreenGraphicsItemPrivate *>( d );
}
<commit_msg>Locking a float item must take effect immediately.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009-2010 Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "ScreenGraphicsItem.h"
#include "ScreenGraphicsItem_p.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleWidget.h"

// Qt
#include <QtGui/QMouseEvent>

using namespace Marble;

ScreenGraphicsItem::ScreenGraphicsItem( MarbleGraphicsItem *parent )
    : MarbleGraphicsItem( new ScreenGraphicsItemPrivate( this, parent ) )
{
}

ScreenGraphicsItem::ScreenGraphicsItem( ScreenGraphicsItemPrivate *d_ptr )
    : MarbleGraphicsItem( d_ptr )
{
}

ScreenGraphicsItem::ScreenGraphicsItem( const QPointF& position, const QSizeF& size,
                                        ScreenGraphicsItemPrivate *d_ptr )
    : MarbleGraphicsItem( d_ptr )
{
    setPosition( position );
    setSize( size );
}

ScreenGraphicsItem::~ScreenGraphicsItem()
{
}

QPointF ScreenGraphicsItem::position() const
{
    return p()->m_position;
}

void ScreenGraphicsItem::setPosition( const QPointF& position )
{
    p()->m_position = position;
}

QPointF ScreenGraphicsItem::positivePosition() const
{
    return p()->positivePosition();
}

QList<QPointF> ScreenGraphicsItem::absolutePositions() const
{
    return p()->absolutePositions();
}

ScreenGraphicsItem::GraphicsItemFlags ScreenGraphicsItem::flags() const
{
    return p()->m_flags;
}

void ScreenGraphicsItem::setFlags( ScreenGraphicsItem::GraphicsItemFlags flags )
{
    p()->m_flags = flags;
}

void ScreenGraphicsItem::changeViewport( ViewportParams *viewport )
{
    Q_UNUSED( viewport );
}

bool ScreenGraphicsItem::eventFilter( QObject *object, QEvent *e )
{
    MarbleWidget *widget = dynamic_cast<MarbleWidget*>(object);
    if ( !widget ) {
        return MarbleGraphicsItem::eventFilter( object, e );
    }

    if ( !p()->m_floatItemMoving ) {
        if ( MarbleGraphicsItem::eventFilter( object, e ) ) {
            return true;
        }

        if ( !visible() || !p()->isMovable() ) {
            return false;
        }

        if ( e->type() == QEvent::MouseMove ) {
            return false;
        }

        // Move ScreenGraphicsItem
        if ( e->type() == QEvent::MouseButtonPress )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>(e);

            // Click and move above a float item triggers moving the float item
            if ( contains( event->pos() ) ) {
                if ( event->button() == Qt::LeftButton ) {
                    p()->m_floatItemMoveStartPos = event->pos();
                    p()->m_floatItemMoving = true;
                    return true;
                }
            }
        }

        return false;
    }
    else {
        // Move ScreenGraphicsItem
        bool cursorAboveFloatItem = false;
        if ( e->type() == QEvent::MouseMove
            || e->type() == QEvent::MouseButtonPress
            || e->type() == QEvent::MouseButtonRelease )
        {
            QMouseEvent *event = static_cast<QMouseEvent*>( e );
            // The rect the item was painted on before. We add one pixel as antialiasing could
            // result into painting on these pixels to.
            QRectF floatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                           size() + QSize( 2, 2 ) );

            // Click and move above a float item triggers moving the float item
            if ( contains( event->pos() ) ) {
                cursorAboveFloatItem = true;

                if ( e->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton ) {
                    p()->m_floatItemMoveStartPos = event->pos();
                    return true;
                }
            }

            if ( e->type() == QEvent::MouseMove && event->buttons() & Qt::LeftButton && p()->isMovable() )
            {
                p()->m_floatItemMoving = true;
                const QPoint &point = event->pos();
                QPointF position = positivePosition();
                qreal newX = position.x()+point.x()-p()->m_floatItemMoveStartPos.x();
                qreal newY = position.y()+point.y()-p()->m_floatItemMoveStartPos.y();
                if ( newX >= 0 && newY >= 0 ) {
                    // docking behavior
                    const qreal dockArea = 60.0; // Alignment area width/height
                    const qreal dockJump = 30.0; // Alignment indicator jump size
                    if ( widget->width()-size().width()-newX < dockArea ) {
                        newX = qMin( qreal( -1.0 ), size().width() + newX-widget->width() );
                        if ( p()->m_floatItemMoveStartPos.x() < event->pos().x() ) {
                            // Indicate change to right alignment with a short jump
                            newX = qMax( newX, -(dockArea-dockJump) );
                        }
                    }
                    if ( widget->height()-size().height()-newY < dockArea ) {
                        newY = qMin( qreal( -1.0 ), size().height() + newY-widget->height() );
                        if (p()->m_floatItemMoveStartPos.y()<event->pos().y()) {
                        // Indicate change to bottom alignment with a short jump
                        newY = qMax( newY, -( dockArea - dockJump ) );
                        }
                    }

                    setPosition( QPointF( newX,newY ) );
                    // The rect the item will be painted on now. We add one pixel as
                    // antialiasing could result into painting on these pixels to.
                    QRect newFloatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
                                                     size() + QSize( 2, 2 ) ).toRect();
                    p()->m_floatItemMoveStartPos = event->pos();
                    QRegion dirtyRegion( floatItemRect.toRect() );
                    dirtyRegion = dirtyRegion.united( newFloatItemRect );

                    widget->setAttribute( Qt::WA_NoSystemBackground,  false );
                    widget->repaint(dirtyRegion);
                    widget->setAttribute( Qt::WA_NoSystemBackground, widget->viewport()->mapCoversViewport() );
                    return true;
                }
            }

            if ( e->type() == QEvent::MouseButtonRelease ) {
                p()->m_floatItemMoving = false;
            }

            // Adjusting Cursor shape
            if ( cursorAboveFloatItem || p()->m_floatItemMoving ) {
                widget->setCursor(QCursor(Qt::SizeAllCursor));
                return true;
            }
        }

        return MarbleGraphicsItem::eventFilter( object, e );
    }
}

ScreenGraphicsItemPrivate *ScreenGraphicsItem::p() const
{
    return reinterpret_cast<ScreenGraphicsItemPrivate *>( d );
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "mbed.h"
#include "rtos.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include "SingletonPtr.h"
#include <stdio.h>

#ifndef MBED_RTOS_SINGLE_THREAD
  #error [NOT_SUPPORTED] test not supported for single threaded enviroment
#endif

using namespace utest::v1;

#define TEST_STACK_SIZE     512
static uint32_t instance_count = 0;

class TestClass {
public:
    TestClass() {
        Thread::wait(500);
        instance_count++;
    }

    void do_something() {
        Thread::wait(100);
    }

    ~TestClass() {
        instance_count--;
    }
};

static TestClass* get_test_class()
{
    static TestClass tc;
    return &tc;
}

static SingletonPtr<TestClass> test_class;

static void main_func_race()
{
    get_test_class();
}

static void main_class_race()
{
    test_class->do_something();
}

void test_case_func_race()
{
    Callback<void()> cb(main_func_race);
    Thread *t1 = new Thread(osPriorityNormal, TEST_STACK_SIZE);
    Thread *t2 = new Thread(osPriorityNormal, TEST_STACK_SIZE);

    // Start start first thread
    t1->start(cb);
    // Start second thread while the first is inside the constructor
    Thread::wait(250);
    t2->start(cb);

    // Wait for the threads to finish
    t1->join();
    t2->join();

    delete t1;
    delete t2;

    TEST_ASSERT_EQUAL_UINT32(1, instance_count);

    // Reset instance count
    instance_count = 0;
}

void test_case_class_race()
{
    Callback<void()> cb(main_class_race);
    Thread *t1 = new Thread(osPriorityNormal, TEST_STACK_SIZE);
    Thread *t2 = new Thread(osPriorityNormal, TEST_STACK_SIZE);

    // Start start first thread
    t1->start(cb);
    // Start second thread while the first is inside the constructor
    Thread::wait(250);
    t2->start(cb);

    // Wait for the threads to finish
    t1->join();
    t2->join();

    delete t1;
    delete t2;

    TEST_ASSERT_EQUAL_UINT32(1, instance_count);

    // Reset instance count
    instance_count = 0;
}

Case cases[] = {
    Case("function init race", test_case_func_race),
    Case("class init race", test_case_class_race),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(20, "default_auto");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    Harness::run(specification);
}
<commit_msg>race tests: fix unsupported condition<commit_after>/*
 * Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "mbed.h"
#include "rtos.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include "SingletonPtr.h"
#include <stdio.h>

#ifdef MBED_RTOS_SINGLE_THREAD
  #error [NOT_SUPPORTED] test not supported for single threaded enviroment
#endif

using namespace utest::v1;

#define TEST_STACK_SIZE     512
static uint32_t instance_count = 0;

class TestClass {
public:
    TestClass() {
        Thread::wait(500);
        instance_count++;
    }

    void do_something() {
        Thread::wait(100);
    }

    ~TestClass() {
        instance_count--;
    }
};

static TestClass* get_test_class()
{
    static TestClass tc;
    return &tc;
}

static SingletonPtr<TestClass> test_class;

static void main_func_race()
{
    get_test_class();
}

static void main_class_race()
{
    test_class->do_something();
}

void test_case_func_race()
{
    Callback<void()> cb(main_func_race);
    Thread *t1 = new Thread(osPriorityNormal, TEST_STACK_SIZE);
    Thread *t2 = new Thread(osPriorityNormal, TEST_STACK_SIZE);

    // Start start first thread
    t1->start(cb);
    // Start second thread while the first is inside the constructor
    Thread::wait(250);
    t2->start(cb);

    // Wait for the threads to finish
    t1->join();
    t2->join();

    delete t1;
    delete t2;

    TEST_ASSERT_EQUAL_UINT32(1, instance_count);

    // Reset instance count
    instance_count = 0;
}

void test_case_class_race()
{
    Callback<void()> cb(main_class_race);
    Thread *t1 = new Thread(osPriorityNormal, TEST_STACK_SIZE);
    Thread *t2 = new Thread(osPriorityNormal, TEST_STACK_SIZE);

    // Start start first thread
    t1->start(cb);
    // Start second thread while the first is inside the constructor
    Thread::wait(250);
    t2->start(cb);

    // Wait for the threads to finish
    t1->join();
    t2->join();

    delete t1;
    delete t2;

    TEST_ASSERT_EQUAL_UINT32(1, instance_count);

    // Reset instance count
    instance_count = 0;
}

Case cases[] = {
    Case("function init race", test_case_func_race),
    Case("class init race", test_case_class_race),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(20, "default_auto");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    Harness::run(specification);
}
<|endoftext|>


<commit_before><commit_msg>Remove the remnants of the late binding experiment.<commit_after><|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Ash Berlin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd.hpp"
#include <curl/curl.h>

using namespace flusspferd;

// Put everything in an anon-namespace so typeid wont clash ever.
namespace {

class curl : public native_object_base {
public:
  struct class_info : public flusspferd::class_info {
    static char const *full_name() { return "cURL"; }
    typedef boost::mpl::bool_<true> constructible;
    static char const *constructor_name() { return "cURL"; }
    static void augment_constructor(object &ctor);
    static object create_prototype();
  };

  curl(object const &obj, call_context &x);
  virtual ~curl();

protected:
  CURL *curlHandle;
  char* error_buffer;

  typedef size_t (*curl_callback_t)(void *, size_t, size_t, void *);

  template<size_t (curl::*Method)(void*, size_t)>
  static size_t c_handle_curl(void *ptr, size_t size, size_t nmemb, void *stream);

  // Data is avilable
  size_t handle_curl_data( void* data, size_t size );
  // Header is available
  size_t handle_curl_header( void* data, size_t size );
  // Data is needed by curl (i.e. upload/request body)
  size_t handle_curl_data_needed( void* buff, size_t size );

  // TODO: Support setting CURLOPT_INFILESIZE for PUT methods

private: // JS methods
  void set_method(string &meth);
  int perform();
};

template<size_t (curl::*Method)(void*, size_t)>
size_t curl::c_handle_curl(void *ptr, size_t size, size_t nmemb, void *stream) {
  curl *self = static_cast<curl*>(stream);
  return (self->*Method)(ptr, size * nmemb);
}

FLUSSPFERD_LOADER(container) {
  load_class<curl>(container);
}

///////////////////////////
void curl::class_info::augment_constructor(object &ctor)
{
  curl_version_info_data* data = curl_version_info(CURLVERSION_NOW);

  if (!data)
    // Very unlikely to happen, but deal with it
    throw exception("Unable to get curl_version_info");

  array protocols = create_array();
  ctor.define_property("supportedProtocols", protocols, read_only_property );

  size_t i = 0;
  for(const char* const* p = data->protocols; *p != NULL; p++, i++) {
    protocols.set_element(i, string( *p ) );
  }
  // Make the properties of the array read only too
  //protocols.seal(false);
  // Arse. Can't in 1.8

  ctor.define_property("versionHex", (int)data->version_num,
                       read_only_property);
  ctor.define_property("versionStr", string( (const char*)data->version),
                       read_only_property);
}

///////////////////////////
object curl::class_info::create_prototype() {
  object proto = create_object();

  create_native_method(proto, "setMethod", &curl::set_method);
  create_native_method(proto, "perform", &curl::perform);

  return proto;
}

///////////////////////////
curl::curl(object const &obj, call_context &)
  : native_object_base(obj),
    error_buffer(NULL)
{
  curlHandle = curl_easy_init();

  if (!curlHandle)
    throw exception("curl_easy_init() failed");

  error_buffer = new char[CURL_ERROR_SIZE];

  curl_callback_t fn_ptr =  &curl::c_handle_curl<&curl::handle_curl_data>;
  curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, fn_ptr);

  fn_ptr =  &curl::c_handle_curl<&curl::handle_curl_header>;
  curl_easy_setopt(curlHandle, CURLOPT_HEADERFUNCTION, fn_ptr);

  fn_ptr =  &curl::c_handle_curl<&curl::handle_curl_data_needed>;
  curl_easy_setopt(curlHandle, CURLOPT_READFUNCTION, fn_ptr);

  curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, this);
  curl_easy_setopt(curlHandle, CURLOPT_HEADERDATA, this);
  curl_easy_setopt(curlHandle, CURLOPT_READDATA, this);
  curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, error_buffer);
  curl_easy_setopt(curlHandle, CURLOPT_ENCODING, "");
}

///////////////////////////
curl::~curl() {
  delete [] error_buffer;
}

///////////////////////////
void curl::set_method(string &f_meth) {
  int ok = CURLE_OK;
  std::string meth = f_meth.to_string();

  if (meth == "GET")
    ok = curl_easy_setopt(curlHandle, CURLOPT_HTTPGET, 1);
  else if (meth == "POST")
    ok = curl_easy_setopt(curlHandle, CURLOPT_POST, 1);
  else if (meth == "PUT")
    ok = curl_easy_setopt(curlHandle, CURLOPT_UPLOAD, 1);
  else if (meth == "HEAD")
    ok = curl_easy_setopt(curlHandle, CURLOPT_NOBODY, 1);
  else
    throw exception(("Unkown request method " + meth).c_str());

  if (ok != CURLE_OK)
    throw exception(error_buffer);
}

///////////////////////////
int curl::perform() {

  local_root_scope scope;
  // Create a copy of URL so that it lives as long as the perform call does
  // curl doesn't copy the CURLOPT_URL param, so it disapearing form under
  // it probably isn't very good
  string url = get_property("url").to_string();
  url = url.substr(0, url.length());

  // TODO: Make POST and PUT do READ_WRITE
  if (!security::get().check_url(url.to_string(), security::READ))
    throw exception("forbidden");

  if (curl_easy_setopt(curlHandle, CURLOPT_URL, url.c_str()) != CURLE_OK)
    throw exception(error_buffer);

  if (curl_easy_perform(curlHandle) != CURLE_OK)
    throw exception(error_buffer);

  long code = 0;
  curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &code);
  // Return value is status code
  return code;
}

size_t curl::handle_curl_data( void *data, size_t nbytes) {
  // See if we have a 'dataReceived' callback defined
  value cb = get_property("dataReceived");

  if (cb.is_function()) {
    object obj = cb.to_object();

    apply(obj,
      create_native_object<blob>(
        object(), (unsigned char const *) data, nbytes));
  }

  return nbytes;
}

size_t curl::handle_curl_header( void *hdr, size_t nbytes ) {
  value cb = get_property("headerReceived");

  if (cb.is_function()) {
    object obj = cb.to_object();

    apply(obj, string((char const *) hdr, nbytes));
  }
  return nbytes;
}

size_t curl::handle_curl_data_needed( void*, size_t ) {
  return 0;
}

} // End of anon namespace
<commit_msg>class_macros/cURL: use new macros for cURL plugin<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Ash Berlin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd.hpp"
#include <curl/curl.h>

using namespace flusspferd;

// Put everything in an anon-namespace so typeid wont clash ever.
namespace {

FLUSSPFERD_CLASS_DESCRIPTION(
  (cpp_name, curl)
  (full_name, "cURL")
  (constructor_name, "cURL")
  (augment_constructor, 1)
  (methods, (setMethod)(perform))
)
public:
  curl(object const &obj, call_context &x);
  virtual ~curl();

protected:
  CURL *curlHandle;
  char* error_buffer;

  typedef size_t (*curl_callback_t)(void *, size_t, size_t, void *);

  template<size_t (curl::*Method)(void*, size_t)>
  static size_t c_handle_curl(void *ptr, size_t size, size_t nmemb, void *stream);

  // Data is avilable
  size_t handle_curl_data( void* data, size_t size );
  // Header is available
  size_t handle_curl_header( void* data, size_t size );
  // Data is needed by curl (i.e. upload/request body)
  size_t handle_curl_data_needed( void* buff, size_t size );

  // TODO: Support setting CURLOPT_INFILESIZE for PUT methods

private: // JS methods
  void setMethod(string &meth);
  int perform();
FLUSSPFERD_CLASS_DESCRIPTION_END()

template<size_t (curl::*Method)(void*, size_t)>
size_t curl::c_handle_curl(void *ptr, size_t size, size_t nmemb, void *stream) {
  curl *self = static_cast<curl*>(stream);
  return (self->*Method)(ptr, size * nmemb);
}

FLUSSPFERD_LOADER(container) {
  load_class<curl>(container);
}

///////////////////////////
void curl::class_info::augment_constructor(object &ctor)
{
  curl_version_info_data* data = curl_version_info(CURLVERSION_NOW);

  if (!data)
    // Very unlikely to happen, but deal with it
    throw exception("Unable to get curl_version_info");

  array protocols = create_array();
  ctor.define_property("supportedProtocols", protocols, read_only_property );

  size_t i = 0;
  for(const char* const* p = data->protocols; *p != NULL; p++, i++) {
    protocols.set_element(i, string( *p ) );
  }
  // Make the properties of the array read only too
  //protocols.seal(false);
  // Arse. Can't in 1.8

  ctor.define_property("versionHex", (int)data->version_num,
                       read_only_property);
  ctor.define_property("versionStr", string( (const char*)data->version),
                       read_only_property);
}

///////////////////////////
curl::curl(object const &obj, call_context &)
  : native_object_base(obj),
    error_buffer(NULL)
{
  curlHandle = curl_easy_init();

  if (!curlHandle)
    throw exception("curl_easy_init() failed");

  error_buffer = new char[CURL_ERROR_SIZE];

  curl_callback_t fn_ptr =  &curl::c_handle_curl<&curl::handle_curl_data>;
  curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, fn_ptr);

  fn_ptr =  &curl::c_handle_curl<&curl::handle_curl_header>;
  curl_easy_setopt(curlHandle, CURLOPT_HEADERFUNCTION, fn_ptr);

  fn_ptr =  &curl::c_handle_curl<&curl::handle_curl_data_needed>;
  curl_easy_setopt(curlHandle, CURLOPT_READFUNCTION, fn_ptr);

  curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, this);
  curl_easy_setopt(curlHandle, CURLOPT_HEADERDATA, this);
  curl_easy_setopt(curlHandle, CURLOPT_READDATA, this);
  curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, error_buffer);
  curl_easy_setopt(curlHandle, CURLOPT_ENCODING, "");
}

///////////////////////////
curl::~curl() {
  delete [] error_buffer;
}

///////////////////////////
void curl::setMethod(string &f_meth) {
  int ok = CURLE_OK;
  std::string meth = f_meth.to_string();

  if (meth == "GET")
    ok = curl_easy_setopt(curlHandle, CURLOPT_HTTPGET, 1);
  else if (meth == "POST")
    ok = curl_easy_setopt(curlHandle, CURLOPT_POST, 1);
  else if (meth == "PUT")
    ok = curl_easy_setopt(curlHandle, CURLOPT_UPLOAD, 1);
  else if (meth == "HEAD")
    ok = curl_easy_setopt(curlHandle, CURLOPT_NOBODY, 1);
  else
    throw exception(("Unkown request method " + meth).c_str());

  if (ok != CURLE_OK)
    throw exception(error_buffer);
}

///////////////////////////
int curl::perform() {

  local_root_scope scope;
  // Create a copy of URL so that it lives as long as the perform call does
  // curl doesn't copy the CURLOPT_URL param, so it disapearing form under
  // it probably isn't very good
  string url = get_property("url").to_string();
  url = url.substr(0, url.length());

  // TODO: Make POST and PUT do READ_WRITE
  if (!security::get().check_url(url.to_string(), security::READ))
    throw exception("forbidden");

  if (curl_easy_setopt(curlHandle, CURLOPT_URL, url.c_str()) != CURLE_OK)
    throw exception(error_buffer);

  if (curl_easy_perform(curlHandle) != CURLE_OK)
    throw exception(error_buffer);

  long code = 0;
  curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &code);
  // Return value is status code
  return code;
}

size_t curl::handle_curl_data( void *data, size_t nbytes) {
  // See if we have a 'dataReceived' callback defined
  value cb = get_property("dataReceived");

  if (cb.is_function()) {
    object obj = cb.to_object();

    apply(obj,
      create_native_object<blob>(
        object(), (unsigned char const *) data, nbytes));
  }

  return nbytes;
}

size_t curl::handle_curl_header( void *hdr, size_t nbytes ) {
  value cb = get_property("headerReceived");

  if (cb.is_function()) {
    object obj = cb.to_object();

    apply(obj, string((char const *) hdr, nbytes));
  }
  return nbytes;
}

size_t curl::handle_curl_data_needed( void*, size_t ) {
  return 0;
}

} // End of anon namespace
<|endoftext|>


<commit_before>
#include <cctype>
#include <iostream>
#include <string>

std::string base64Encode( const std::string& str ) {
    // The base64 character set. We use `-` and `_` instead of `+` and `/`.
    const char b64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

    // Base64 turns 3 8-bit chars into 4 6-bit characters, thus requiring 4*n/3 (or about 1.34x)
    // Also, this automatically adds padding symbols at the end of the string.
    const size_t length = str.size();
    std::string retval( (((length + 2) / 3) * 4), '=' );

    std::size_t outpos          = 0;
    int bitsCollected           = 0;
    unsigned int accumulator    = 0;

    // Work on every character of the source string...
    for( int i = 0; i < length; i++ ){
        accumulator = (accumulator << 8) | (str[i] & 0xffu);
        bitsCollected += 8;

        // ...and add groups of 6 bits to the resulting string.
        // Remember that 3 real bytes = 4 base64 bytes
        while( bitsCollected >= 6 ){
            bitsCollected -= 6;
            retval[ outpos++ ] = b64Table[ (accumulator >> bitsCollected) & 0x3fu ];
        }
    }

    // Sometimes, some bits are left over. Forcibly add these to the string.
    if( bitsCollected > 0 ){
        accumulator <<= 6 - bitsCollected;
        retval[ outpos++ ] = b64Table[ accumulator & 0x3fu ];
    }

    return std::move( retval );
}

// ------------------------------------------------------------------------------------------ //

std::string base64Decode( const std::string& encoded ){
    // Prepare our string, reserving an estimate of how large the result will be.
    std::string decoded;
    decoded.reserve( encoded.size() * 3 / 4 );

    // Loop through the string, decoding the characters in batches of 4.
    char chars[ 4 ] = { 0 };
    int padding = 0;
    for( std::size_t i = 0; i < encoded.size(); ++i ){
        // Don't bother decoding any padding.
        const char c = encoded[ i ];

        // Decode this character.
        chars[ i % 4 ] =
            std::isupper( c ) ? c - 'A' +  0 :
            std::islower( c ) ? c - 'a' + 26 :
            std::isdigit( c ) ? c - '0' + 52 :
            c == '-' ? 62 :
            c == '/' ? 63 : (++padding, 0)
        ;

        // Every 4 characters we decode 3 characters and append them to the output.
        if( i % 4 == 3 ){
            decoded.append( 1, (chars[ 0 ] << 2) + ((chars[ 1 ] & 0x30) >> 4) );
            if( padding <= 1 ){
                decoded.append( 1, ((chars[ 1 ] & 0x0f) << 4) + ((chars[ 2 ] & 0x3c) >> 2) );
            }
            if( padding == 0 ){
                decoded.append( 1, ((chars[ 2 ] & 0x03) << 6) + chars[ 3 ] );
            }
        }
    }

    return std::move( decoded );
}

int main( void ){
    std::cout << "\"\"          \"" << base64Encode( ""       ) << "\"" << std::endl;
    std::cout << "\"Zg==\"      \"" << base64Encode( "f"      ) << "\"" << std::endl;
    std::cout << "\"Zm8=\"      \"" << base64Encode( "fo"     ) << "\"" << std::endl;
    std::cout << "\"Zm9v\"      \"" << base64Encode( "foo"    ) << "\"" << std::endl;
    std::cout << "\"Zm9vYg==\"  \"" << base64Encode( "foob"   ) << "\"" << std::endl;
    std::cout << "\"Zm9vYmE=\"  \"" << base64Encode( "fooba"  ) << "\"" << std::endl;
    std::cout << "\"Zm9vYmFy\"  \"" << base64Encode( "foobar" ) << "\"" << std::endl;

    std::cout << "\"\"          \"" << base64Decode( ""           ) << "\"" << std::endl;
    std::cout << "\"f\"         \"" << base64Decode( "Zg=="       ) << "\"" << std::endl;
    std::cout << "\"fo\"        \"" << base64Decode( "Zm8="       ) << "\"" << std::endl;
    std::cout << "\"foo\"       \"" << base64Decode( "Zm9v"       ) << "\"" << std::endl;
    std::cout << "\"foob\"      \"" << base64Decode( "Zm9vYg=="   ) << "\"" << std::endl;
    std::cout << "\"fooba\"     \"" << base64Decode( "Zm9vYmE="   ) << "\"" << std::endl;
    std::cout << "\"foobar\"    \"" << base64Decode( "Zm9vYmFy"   ) << "\"" << std::endl;
}
<commit_msg>Fixed bug in decode<commit_after>
#include <cctype>
#include <iostream>
#include <string>

std::string base64Encode( const std::string& str ) {
    // The base64 character set. We use `-` and `_` instead of `+` and `/`.
    const char b64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

    // Base64 turns 3 8-bit chars into 4 6-bit characters, thus requiring 4*n/3 (or about 1.34x)
    // Also, this automatically adds padding symbols at the end of the string.
    const size_t length = str.size();
    std::string retval( (((length + 2) / 3) * 4), '=' );

    std::size_t outpos          = 0;
    int bitsCollected           = 0;
    unsigned int accumulator    = 0;

    // Work on every character of the source string...
    for( int i = 0; i < length; i++ ){
        accumulator = (accumulator << 8) | (str[i] & 0xffu);
        bitsCollected += 8;

        // ...and add groups of 6 bits to the resulting string.
        // Remember that 3 real bytes = 4 base64 bytes
        while( bitsCollected >= 6 ){
            bitsCollected -= 6;
            retval[ outpos++ ] = b64Table[ (accumulator >> bitsCollected) & 0x3fu ];
        }
    }

    // Sometimes, some bits are left over. Forcibly add these to the string.
    if( bitsCollected > 0 ){
        accumulator <<= 6 - bitsCollected;
        retval[ outpos++ ] = b64Table[ accumulator & 0x3fu ];
    }

    return std::move( retval );
}

// ------------------------------------------------------------------------------------------ //

std::string base64Decode( const std::string& encoded ){
    // Prepare our string, reserving an estimate of how large the result will be.
    std::string decoded;
    decoded.reserve( encoded.size() * 3 / 4 );

    // Loop through the string, decoding the characters in batches of 4.
    char chars[ 4 ] = { 0 };
    int padding = 0;
    for( std::size_t i = 0; i < encoded.size(); ++i ){
        // Don't bother decoding any padding.
        const char c = encoded[ i ];

        // Decode this character.
        chars[ i % 4 ] =
            std::isupper( c ) ? c - 'A' +  0 :
            std::islower( c ) ? c - 'a' + 26 :
            std::isdigit( c ) ? c - '0' + 52 :
            c == '-' ? 62 :
            c == '_' ? 63 : (++padding, 0)
        ;

        // Every 4 characters we decode 3 characters and append them to the output.
        if( i % 4 == 3 ){
            decoded.append( 1, (chars[ 0 ] << 2) + ((chars[ 1 ] & 0x30) >> 4) );
            if( padding <= 1 ){
                decoded.append( 1, ((chars[ 1 ] & 0x0f) << 4) + ((chars[ 2 ] & 0x3c) >> 2) );
            }
            if( padding == 0 ){
                decoded.append( 1, ((chars[ 2 ] & 0x03) << 6) + chars[ 3 ] );
            }
        }
    }

    return std::move( decoded );
}

int main( void ){
    std::cout << "\"\"          \"" << base64Encode( ""       ) << "\"" << std::endl;
    std::cout << "\"Zg==\"      \"" << base64Encode( "f"      ) << "\"" << std::endl;
    std::cout << "\"Zm8=\"      \"" << base64Encode( "fo"     ) << "\"" << std::endl;
    std::cout << "\"Zm9v\"      \"" << base64Encode( "foo"    ) << "\"" << std::endl;
    std::cout << "\"Zm9vYg==\"  \"" << base64Encode( "foob"   ) << "\"" << std::endl;
    std::cout << "\"Zm9vYmE=\"  \"" << base64Encode( "fooba"  ) << "\"" << std::endl;
    std::cout << "\"Zm9vYmFy\"  \"" << base64Encode( "foobar" ) << "\"" << std::endl;

    std::cout << "\"\"          \"" << base64Decode( ""           ) << "\"" << std::endl;
    std::cout << "\"f\"         \"" << base64Decode( "Zg=="       ) << "\"" << std::endl;
    std::cout << "\"fo\"        \"" << base64Decode( "Zm8="       ) << "\"" << std::endl;
    std::cout << "\"foo\"       \"" << base64Decode( "Zm9v"       ) << "\"" << std::endl;
    std::cout << "\"foob\"      \"" << base64Decode( "Zm9vYg=="   ) << "\"" << std::endl;
    std::cout << "\"fooba\"     \"" << base64Decode( "Zm9vYmE="   ) << "\"" << std::endl;
    std::cout << "\"foobar\"    \"" << base64Decode( "Zm9vYmFy"   ) << "\"" << std::endl;
}
<|endoftext|>


<commit_before>#include "QuadraturePoints.h"

// ---------------------------------------------------------------------------

cigma::QuadraturePoints::QuadraturePoints()
{
    qdim = 0;
    qpts = 0;
    qwts = 0;
}

cigma::QuadraturePoints::~QuadraturePoints()
{
    if (qpts != 0) delete [] qpts;
    if (qwts != 0) delete [] qwts;
    //if (data != 0) delete [] data; //XXX: why does it crash here?
}

// ---------------------------------------------------------------------------

void cigma::QuadraturePoints::set_quadrature(double *quadpts, double *quadwts, int npts, int qdim)
{
    /* some basic assertions */
    assert(quadpts != 0);
    assert(quadwts != 0);
    assert(npts > 0);
    assert(qdim > 0);

    /* clear existing data */
    if (qpts != 0) delete [] qpts;
    if (qwts != 0) delete [] qwts;

    /* set dimensions */
    this->num = npts;
    this->qdim = qdim;

    /* allocate new data arrays */
    qpts = new double[num * qdim];
    qwts = new double[num];

    /* copy from quadpts & quadwts */
    int i,j;
    for (i = 0; i < num; i++)
    {
        qwts[i] = quadwts[i];
        for (j = 0; j < qdim; j++)
        {
            int n = qdim*i + j;
            qpts[n] = quadpts[n];
        }
    }
}

void cigma::QuadraturePoints::set_globaldim(int dim)
{
    assert(num > 0);
    this->dim = dim;
    this->data = new double[num * dim];
    for (int i = 0; i < num; i++)
    {
        for (int j = 0; j < dim; j++)
        {
            data[dim*i+j] = 0.0;
        }
    }
}

void cigma::QuadraturePoints::apply_refmap(Cell *cell)
{
    assert(cell != 0);
    assert(data != 0);

    for (int i = 0; i < num; i++)
    {
        double *uvw = &qpts[qdim*i];
        double *xyz = &data[dim*i];
        cell->uvw2xyz(uvw, xyz);
    }
}

// ---------------------------------------------------------------------------
<commit_msg>A QuadraturePoints object need not manage its parent data pointer<commit_after>#include "QuadraturePoints.h"

// ---------------------------------------------------------------------------

cigma::QuadraturePoints::QuadraturePoints()
{
    qdim = 0;
    qpts = 0;
    qwts = 0;
}

cigma::QuadraturePoints::~QuadraturePoints()
{
    if (qpts != 0) delete [] qpts;
    if (qwts != 0) delete [] qwts;
}

// ---------------------------------------------------------------------------

void cigma::QuadraturePoints::set_quadrature(double *quadpts, double *quadwts, int npts, int qdim)
{
    /* some basic assertions */
    assert(quadpts != 0);
    assert(quadwts != 0);
    assert(npts > 0);
    assert(qdim > 0);

    /* clear existing data */
    if (qpts != 0) delete [] qpts;
    if (qwts != 0) delete [] qwts;

    /* set dimensions */
    this->num = npts;
    this->qdim = qdim;

    /* allocate new data arrays */
    qpts = new double[num * qdim];
    qwts = new double[num];

    /* copy from quadpts & quadwts */
    int i,j;
    for (i = 0; i < num; i++)
    {
        qwts[i] = quadwts[i];
        for (j = 0; j < qdim; j++)
        {
            int n = qdim*i + j;
            qpts[n] = quadpts[n];
        }
    }
}

void cigma::QuadraturePoints::set_globaldim(int dim)
{
    assert(num > 0);
    this->dim = dim;
    this->data = new double[num * dim];
    for (int i = 0; i < num; i++)
    {
        for (int j = 0; j < dim; j++)
        {
            data[dim*i+j] = 0.0;
        }
    }
}

void cigma::QuadraturePoints::apply_refmap(Cell *cell)
{
    assert(cell != 0);
    assert(data != 0);

    for (int i = 0; i < num; i++)
    {
        double *uvw = &qpts[qdim*i];
        double *xyz = &data[dim*i];
        cell->uvw2xyz(uvw, xyz);
    }
}

// ---------------------------------------------------------------------------
<|endoftext|>


<commit_before>#include <gbAudio/impl/QueuedSource_OAL.hpp>

#include <gbAudio/impl/Buffer_OAL.hpp>
#include <gbAudio/impl/Error_OAL.hpp>

#include <gbAudio/Exceptions.hpp>

#include <gbBase/Assert.hpp>
#include <gbBase/Exception.hpp>
#include <gbBase/Log.hpp>

namespace GHULBUS_AUDIO_NAMESPACE
{
namespace impl
{

QueuedSource_OAL::QueuedSource_OAL(ALuint source_id)
    :m_source(source_id), m_userRequestedPlayState(State::Stopped)
{
}

QueuedSource_OAL::~QueuedSource_OAL()
{
    ErrorMonitor_OAL monitor;
    GHULBUS_LOG(Debug, "Deleting queued source #" << m_source << ".");
    alDeleteSources(1, &m_source);
}

void QueuedSource_OAL::play()
{
    GHULBUS_LOG(Trace, "Playing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePlay(m_source);
    m_userRequestedPlayState = State::Playing;
}

void QueuedSource_OAL::pause()
{
    GHULBUS_LOG(Trace, "Pausing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePause(m_source);
    m_userRequestedPlayState = State::Paused;
}

void QueuedSource_OAL::stop()
{
    GHULBUS_LOG(Trace, "Stopping queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceStop(m_source);
    m_userRequestedPlayState = State::Stopped;
}

void QueuedSource_OAL::rewind()
{
    GHULBUS_LOG(Trace, "Rewinding queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceRewind(m_source);
}

Playable::State QueuedSource_OAL::getPlayState() const
{
    ALint state;
    alGetSourcei(m_source, AL_SOURCE_STATE, &state);
    switch(state)
    {
    case AL_PLAYING: return State::Playing;
    case AL_PAUSED:  return State::Paused;
    default:         return State::Stopped;
    }
}

void QueuedSource_OAL::loop(bool do_loop)
{
    ErrorMonitor_OAL monitor;
    alSourcei(m_source, AL_LOOPING, (do_loop) ? AL_TRUE : AL_FALSE);
}

bool QueuedSource_OAL::isLooping() const
{
    ALint ret;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_LOOPING, &ret);
    return (ret == AL_TRUE);
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer)
{
    enqueueBuffer(buffer, BufferProcessedCallback());
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer, BufferProcessedCallback cb)
{
    auto& oal_buffer = dynamic_cast<Buffer_OAL&>(buffer);
    ALuint const buffer_id = oal_buffer.getBufferId_OAL();
    m_queue.emplace_back(&oal_buffer, std::move(cb));
    ErrorMonitor_OAL monitor;
    alSourceQueueBuffers(m_source, 1, &buffer_id);
    if(monitor.checkError()) {
        m_queue.pop_back();
        GHULBUS_THROW(Exceptions::OpenALError(), "Error when queuing buffers to source.");
    }
}

void QueuedSource_OAL::pump()
{
    ALint buffers_processed;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &buffers_processed);
    if(buffers_processed == 0) { return; }
    std::vector<ALuint> free_buffers(buffers_processed);
    alSourceUnqueueBuffers(m_source, buffers_processed, free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while unqueuing buffers from source.");
    }

    std::vector<ALuint> reinserted_buffers;
    auto it = begin(free_buffers);
    while(it != end(free_buffers)) {
        auto const qe = m_queue.front();
        GHULBUS_ASSERT(qe.buffer->getBufferId_OAL() == *it);
        auto const buffer_action = qe.cb(*qe.buffer);
        if(buffer_action == BufferAction::Reinsert) {
            m_queue.push_back(qe);
            ++it;
        } else {
            GHULBUS_ASSERT(buffer_action == BufferAction::Drop);
            it = free_buffers.erase(it);
        }
        m_queue.pop_front();
    }

    if(!free_buffers.empty()) {
        alSourceQueueBuffers(m_source, static_cast<ALsizei>(free_buffers.size()), free_buffers.data());
        if(monitor.checkError()) {
            GHULBUS_THROW(Exceptions::OpenALError(), "Error while re-queuing buffers to source.");
        }
        // If a source stopped playing because it ran out of buffers, reinserting buffers will resume playback
        if(m_userRequestedPlayState == State::Playing && getPlayState() == State::Stopped)
        {
            alSourcePlay(m_source);
        }
    }
}

void QueuedSource_OAL::clearQueue()
{
    GHULBUS_PRECONDITION(getPlayState() == State::Stopped);
    ErrorMonitor_OAL monitor;
    std::vector<ALuint> free_buffers(m_queue.size());
    alSourceUnqueueBuffers(m_source, static_cast<ALsizei>(m_queue.size()), free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while clearing buffer queue on source.");
    }
}

}
}
<commit_msg>queued source reinserted buffer is now reserved upfront<commit_after>#include <gbAudio/impl/QueuedSource_OAL.hpp>

#include <gbAudio/impl/Buffer_OAL.hpp>
#include <gbAudio/impl/Error_OAL.hpp>

#include <gbAudio/Exceptions.hpp>

#include <gbBase/Assert.hpp>
#include <gbBase/Exception.hpp>
#include <gbBase/Log.hpp>

namespace GHULBUS_AUDIO_NAMESPACE
{
namespace impl
{

QueuedSource_OAL::QueuedSource_OAL(ALuint source_id)
    :m_source(source_id), m_userRequestedPlayState(State::Stopped)
{
}

QueuedSource_OAL::~QueuedSource_OAL()
{
    ErrorMonitor_OAL monitor;
    GHULBUS_LOG(Debug, "Deleting queued source #" << m_source << ".");
    alDeleteSources(1, &m_source);
}

void QueuedSource_OAL::play()
{
    GHULBUS_LOG(Trace, "Playing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePlay(m_source);
    m_userRequestedPlayState = State::Playing;
}

void QueuedSource_OAL::pause()
{
    GHULBUS_LOG(Trace, "Pausing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePause(m_source);
    m_userRequestedPlayState = State::Paused;
}

void QueuedSource_OAL::stop()
{
    GHULBUS_LOG(Trace, "Stopping queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceStop(m_source);
    m_userRequestedPlayState = State::Stopped;
}

void QueuedSource_OAL::rewind()
{
    GHULBUS_LOG(Trace, "Rewinding queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceRewind(m_source);
}

Playable::State QueuedSource_OAL::getPlayState() const
{
    ALint state;
    alGetSourcei(m_source, AL_SOURCE_STATE, &state);
    switch(state)
    {
    case AL_PLAYING: return State::Playing;
    case AL_PAUSED:  return State::Paused;
    default:         return State::Stopped;
    }
}

void QueuedSource_OAL::loop(bool do_loop)
{
    ErrorMonitor_OAL monitor;
    alSourcei(m_source, AL_LOOPING, (do_loop) ? AL_TRUE : AL_FALSE);
}

bool QueuedSource_OAL::isLooping() const
{
    ALint ret;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_LOOPING, &ret);
    return (ret == AL_TRUE);
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer)
{
    enqueueBuffer(buffer, BufferProcessedCallback());
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer, BufferProcessedCallback cb)
{
    auto& oal_buffer = dynamic_cast<Buffer_OAL&>(buffer);
    ALuint const buffer_id = oal_buffer.getBufferId_OAL();
    m_queue.emplace_back(&oal_buffer, std::move(cb));
    ErrorMonitor_OAL monitor;
    alSourceQueueBuffers(m_source, 1, &buffer_id);
    if(monitor.checkError()) {
        m_queue.pop_back();
        GHULBUS_THROW(Exceptions::OpenALError(), "Error when queuing buffers to source.");
    }
}

void QueuedSource_OAL::pump()
{
    ALint buffers_processed;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &buffers_processed);
    if(buffers_processed == 0) { return; }
    std::vector<ALuint> free_buffers(buffers_processed);
    alSourceUnqueueBuffers(m_source, buffers_processed, free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while unqueuing buffers from source.");
    }

    std::vector<ALuint> reinserted_buffers;
    reinserted_buffers.reserve(free_buffers.size());        // we assume that reinsertion is the typical case
    auto it = begin(free_buffers);
    while(it != end(free_buffers)) {
        auto const qe = m_queue.front();
        GHULBUS_ASSERT(qe.buffer->getBufferId_OAL() == *it);
        auto const buffer_action = qe.cb(*qe.buffer);
        if(buffer_action == BufferAction::Reinsert) {
            m_queue.push_back(qe);
            ++it;
        } else {
            GHULBUS_ASSERT(buffer_action == BufferAction::Drop);
            it = free_buffers.erase(it);
        }
        m_queue.pop_front();
    }

    if(!free_buffers.empty()) {
        alSourceQueueBuffers(m_source, static_cast<ALsizei>(free_buffers.size()), free_buffers.data());
        if(monitor.checkError()) {
            GHULBUS_THROW(Exceptions::OpenALError(), "Error while re-queuing buffers to source.");
        }
        // If a source stopped playing because it ran out of buffers, reinserting buffers will resume playback
        if(m_userRequestedPlayState == State::Playing && getPlayState() == State::Stopped)
        {
            alSourcePlay(m_source);
        }
    }
}

void QueuedSource_OAL::clearQueue()
{
    GHULBUS_PRECONDITION(getPlayState() == State::Stopped);
    ErrorMonitor_OAL monitor;
    std::vector<ALuint> free_buffers(m_queue.size());
    alSourceUnqueueBuffers(m_source, static_cast<ALsizei>(m_queue.size()), free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while clearing buffer queue on source.");
    }
}

}
}
<|endoftext|>