<commit_before>#include "singleton_factory.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "processor_facedetect.hpp"
#include "include/rapidjson/document.h"
#include <algorithm>
#include <iostream>
#include <cmath>

class EyeTrackProcessor : public Processor {
  public:
    cv::Mat operator()(cv::Mat);
    EyeTrackProcessor();
    virtual ~EyeTrackProcessor(){};
    void init(const char*); // Add image to paste
    std::string getParameters();
  private:
    void drawBorder( cv::Mat );
    void calcGradient( cv::Mat );
    cv::Rect getRightEyeRoI( cv::Mat);
    cv::Rect getLeftEyeRoI( cv::Mat);
    static void createOutput(cv::Mat&, cv::Mat&);
    // Helper function for debugging
    static void printDim( const std::string&, const cv::Mat&);
    std::unique_ptr<FaceDetectorProcessor> innerFaceDetector;
    // Parameters for eye location in units of face width,height
    double eyeWidth = 0.3;
    double eyeHeight = 0.3;
    double eyeX0 = 0.15;
    double eyeY0 = 0.25;
    int useQuantile = 0;
    double gradThreshQuantile = 0.75;
    double gradThreshStdScale = 0.5;
    int ksize = CV_SCHARR;
};

EyeTrackProcessor::EyeTrackProcessor() {
  // Use inner FaceDetector processor for finding faces in image
  innerFaceDetector = std::unique_ptr<FaceDetectorProcessor>{new FaceDetectorProcessor()};
}

void EyeTrackProcessor::init( const char* json ) {
  using namespace rapidjson;
  Document document;

  document.Parse(json);
  assert(document.IsObject());
  assert(document.HasMember("useQuantile"));
  useQuantile = document["useQuantile"].GetInt();
  gradThreshQuantile = document["qscale"].GetDouble();
  gradThreshStdScale = document["sscale"].GetDouble();
  ksize = document["ksize"].GetInt();
}

std::string EyeTrackProcessor::getParameters() {
  std::ostringstream os;
  os <<  "{\"useQuantile\":" << useQuantile << "," <<
         "\"qscale\":" << gradThreshQuantile << "," <<
         "\"sscale\":" << gradThreshStdScale << "," <<
         "\"ksize\":" << ksize << "}";
  return os.str();
}

void EyeTrackProcessor::printDim(const std::string& name, const cv::Mat& im) {
  std::cout << name << ": " << im.rows << "x" << im.cols
            << "x" << im.channels() << std::endl;
}

cv::Mat EyeTrackProcessor::operator()(cv::Mat im) {
  // EyeTrack segmentation demo from the OpenCV documentation
  cv::cvtColor( im, im, CV_RGBA2BGR );

  std::vector<cv::Rect> faces;
  innerFaceDetector->detectFaces(im, faces);

  for ( size_t i=0; i < faces.size(); i++ ) {
    // Whole face RoI
    cv::Mat imFace = im( faces[i] );
    cv::Rect rightEye = getRightEyeRoI(imFace);
    // Person left eye (camera right)
    cv::Rect leftEye = getLeftEyeRoI(imFace);

    calcGradient(imFace(rightEye));
    calcGradient(imFace(leftEye));

    drawBorder(imFace(rightEye));
    drawBorder(imFace(leftEye));
  }

  // Display intermediate images for debugging
  // cv::Mat dest;
  // createOutput( markers, dest );
  cv::cvtColor( im, im, CV_BGR2RGBA );
  return im;
}

void EyeTrackProcessor::drawBorder( cv::Mat im){
    cv::Rect border(0,0,im.cols,im.rows);
    cv::rectangle( im, border, cv::Scalar(0,255,0), 1);
}

void EyeTrackProcessor::calcGradient( cv::Mat im) {
  // Takes input BGR image and calculates gradient after smoothing
  // Remove noise by blurring with Gaussian

  cv::Mat imC;
  im.copyTo(imC);
  cv::GaussianBlur(imC, imC, cv::Size(3,3), 0,0, cv::BORDER_DEFAULT);
  cv::Mat grey(imC.size(), CV_8UC1);
  cv::cvtColor( imC, grey, CV_BGR2GRAY);

  int scale = 1;
  int delta = 0;
  int ddepth = CV_16S;
  cv::Mat grad(grey.size(), CV_8UC2);
  std::vector<cv::Mat> gradV(2);
  cv::Sobel(grey, gradV[0], ddepth, 1, 0, ksize, scale, delta, cv::BORDER_DEFAULT);
  cv::Sobel(grey, gradV[1], ddepth, 0, 1, ksize, scale, delta, cv::BORDER_DEFAULT);
  cv::merge( gradV, grad);

  // Normalized gradient - need to convert to float
  cv::Mat nGrad;
  grad.convertTo(nGrad, CV_32FC1);
  cv::normalize(nGrad, nGrad, 1);
  printDim( "grad", grad);
  printDim( "nGrad", nGrad);
  std::cout << cv::norm( nGrad ) << std::endl;
  /*
  cv::Mat nGradNorm; // Check: norm of elements should sum to 1
  nGrad.copyTo( nGradNorm );
  nGradNorm = nGradNorm.reshape(1, nGrad.rows*nGrad.cols);
  cv::pow( nGradNorm, 2, nGradNorm);
  cv::Mat nGradNormSum;
  cv::reduce(nGradNorm, nGradNormSum, 1, CV_REDUCE_SUM);
  cv::sqrt( nGradNormSum, nGradNormSum);
  nGradNormSum = nGradNormSum.reshape(0, nGrad.rows);
  std::cout << nGradNormSum << std::endl;
  */

  // Convert to 8U1
  cv::Mat absGrad;
  cv::convertScaleAbs(grad, absGrad);
  cv::Mat gradient;
  gradient = absGrad.reshape(1, grad.rows*grad.cols);

  cv::reduce(gradient, gradient, 1, CV_REDUCE_AVG, -1);
  // cv::addWeighted(absGrad.col(0), 0.5, absGrad.col(1), 0.5, 0, gradient);
  gradient = gradient.reshape(0, grad.rows);
  // cv::addWeighted(absGradX, 0.5, absGradY, 0.5, 0, gradient);
  std::cout << "Thresholding" << std::endl;
  std::cout << gradient.rows << "x" << gradient.cols << std::endl;
  // std::cout << gradient << std::endl;
  if ( useQuantile == 1 ) {
    // Threshold by quantile
    std::vector<int> gradVals;
    gradient.reshape(0,1).copyTo(gradVals);
    std::sort(gradVals.begin(), gradVals.end());
    int gradThresh = gradVals[std::floor(gradThreshQuantile*gradVals.size())];
    cv::threshold( gradient, gradient, gradThresh, 255, cv::THRESH_TOZERO);
  } else {
    // Threshold to remove small gradient values
    cv::Scalar gradMean;
    cv::Scalar gradStd;
    cv::meanStdDev( gradient, gradMean, gradStd);
    cv::Scalar gradThreshold;
    cv::addWeighted(gradMean,1.0, gradStd, gradThreshStdScale, 0, gradThreshold);
    cv::threshold( gradient, gradient, gradThreshold.val[0], 255, cv::THRESH_TOZERO);
  }

  cv::Mat dest( gradient.size(), CV_8UC3);
  std::cout << "Gradient: " << gradient.channels() <<
              ", Dest: " << dest.channels() << std::endl;

  cv::cvtColor( gradient, dest, CV_GRAY2BGR);
  dest.copyTo(im);
}

cv::Rect EyeTrackProcessor::getRightEyeRoI( cv::Mat imFace ) {
    int faceWidth = imFace.cols;
    int faceHeight = imFace.rows;
    int w = std::round( faceWidth * eyeWidth);
    int h = std::round( faceHeight * eyeHeight);
    int x0 = std::round( faceWidth * eyeX0);
    int y0 = std::round( faceHeight * eyeY0);
    // Person right eye (camera left)
    cv::Rect roiRightEye(x0, y0, w, h);
    return roiRightEye;
}

cv::Rect EyeTrackProcessor::getLeftEyeRoI( cv::Mat imFace ) {
    int faceWidth = imFace.cols;
    int faceHeight = imFace.rows;
    int w = std::round( faceWidth * eyeWidth);
    int h = std::round( faceHeight * eyeHeight);
    int x0 = std::round( faceWidth * eyeX0);
    int y0 = std::round( faceHeight * eyeY0);
    // Person right eye (camera left)
    cv::Rect roiLeftEye(faceWidth - x0 - w, y0, w, h);
    return roiLeftEye;
}

void EyeTrackProcessor::createOutput( cv::Mat& src, cv::Mat& dest )
{
  // Show intermediate images - need to expand CV_8UC1 to RGBA
  cv::Mat fullAlpha = cv::Mat( src.size(), CV_8UC1, cv::Scalar(255));
  std::vector<cv::Mat> rgba_out;
  rgba_out.push_back( src );
  rgba_out.push_back( src );
  rgba_out.push_back( src );
  rgba_out.push_back( fullAlpha );

  cv::merge( rgba_out, dest);
}

namespace {
  auto scProcReg = ProcessorRegister<EyeTrackProcessor>("Eye Tracker");
}
<commit_msg>Working on gradient calculation for eye tracking.<commit_after>#include "singleton_factory.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "processor_facedetect.hpp"
#include "include/rapidjson/document.h"
#include <algorithm>
#include <iostream>
#include <cmath>

class EyeTrackProcessor : public Processor {
  public:
    cv::Mat operator()(cv::Mat);
    EyeTrackProcessor();
    virtual ~EyeTrackProcessor(){};
    void init(const char*); // Add image to paste
    std::string getParameters();
  private:
    void drawBorder( cv::Mat );
    void calcGradient( cv::Mat );
    cv::Rect getRightEyeRoI( const cv::Mat&);
    cv::Rect getLeftEyeRoI( const cv::Mat&);
    static void createOutput(cv::Mat&, cv::Mat&);
    // Helper function for debugging
    static void printDim( const std::string&, const cv::Mat&);
    std::unique_ptr<FaceDetectorProcessor> innerFaceDetector;
    // Parameters for eye location in units of face width,height
    double eyeWidth = 0.3;
    double eyeHeight = 0.3;
    double eyeX0 = 0.15;
    double eyeY0 = 0.25;
    int useQuantile = 0;
    double gradThreshQuantile = 0.75;
    double gradThreshStdScale = 0.5;
    int ksize = CV_SCHARR;
};

EyeTrackProcessor::EyeTrackProcessor() {
  // Use inner FaceDetector processor for finding faces in image
  innerFaceDetector = std::unique_ptr<FaceDetectorProcessor>{new FaceDetectorProcessor()};
}

void EyeTrackProcessor::init( const char* json ) {
  using namespace rapidjson;
  Document document;

  document.Parse(json);
  assert(document.IsObject());
  assert(document.HasMember("useQuantile"));
  useQuantile = document["useQuantile"].GetInt();
  gradThreshQuantile = document["qscale"].GetDouble();
  gradThreshStdScale = document["sscale"].GetDouble();
  ksize = document["ksize"].GetInt();
}

std::string EyeTrackProcessor::getParameters() {
  std::ostringstream os;
  os <<  "{\"useQuantile\":" << useQuantile << "," <<
         "\"qscale\":" << gradThreshQuantile << "," <<
         "\"sscale\":" << gradThreshStdScale << "," <<
         "\"ksize\":" << ksize << "}";
  return os.str();
}

void EyeTrackProcessor::printDim(const std::string& name, const cv::Mat& im) {
  std::cout << name << ": " << im.rows << "x" << im.cols
            << "x" << im.channels() << std::endl;
}

cv::Mat EyeTrackProcessor::operator()(cv::Mat im) {
  // EyeTrack segmentation demo from the OpenCV documentation
  cv::cvtColor( im, im, CV_RGBA2BGR );

  std::vector<cv::Rect> faces;
  innerFaceDetector->detectFaces(im, faces);

  for ( size_t i=0; i < faces.size(); i++ ) {
    // Whole face RoI
    cv::Mat imFace = im( faces[i] );
    cv::Rect rightEye = getRightEyeRoI(imFace);
    // Person left eye (camera right)
    cv::Rect leftEye = getLeftEyeRoI(imFace);

    calcGradient(imFace(rightEye));
    calcGradient(imFace(leftEye));

    drawBorder(imFace(rightEye));
    drawBorder(imFace(leftEye));
  }

  // Display intermediate images for debugging
  // cv::Mat dest;
  // createOutput( markers, dest );
  cv::cvtColor( im, im, CV_BGR2RGBA );
  return im;
}

void EyeTrackProcessor::drawBorder( cv::Mat im){
    cv::Rect border(0,0,im.cols,im.rows);
    cv::rectangle( im, border, cv::Scalar(0,255,0), 1);
}

void EyeTrackProcessor::calcGradient( cv::Mat im) {
  // Takes input BGR image and calculates gradient after smoothing
  // Remove noise by blurring with Gaussian

  cv::Mat imC;
  im.copyTo(imC);
  cv::GaussianBlur(imC, imC, cv::Size(3,3), 0,0, cv::BORDER_DEFAULT);
  cv::Mat grey(imC.size(), CV_8UC1);
  cv::cvtColor( imC, grey, CV_BGR2GRAY);

  int scale = 1;
  int delta = 0;
  int ddepth = CV_64F;
  cv::Mat grad(grey.size(), CV_64FC2);
  std::vector<cv::Mat> gradV(2);
  cv::Sobel(grey, gradV[0], ddepth, 1, 0, ksize, scale, delta, cv::BORDER_DEFAULT);
  cv::Sobel(grey, gradV[1], ddepth, 0, 1, ksize, scale, delta, cv::BORDER_DEFAULT);
  cv::merge( gradV, grad);

  // Convert to 8U1
  cv::Mat absGrad;
  cv::convertScaleAbs(grad, absGrad);
  cv::Mat gradient;
  gradient = absGrad.reshape(1, grad.rows*grad.cols);

  cv::reduce(gradient, gradient, 1, CV_REDUCE_AVG, -1);
  // cv::addWeighted(absGrad.col(0), 0.5, absGrad.col(1), 0.5, 0, gradient);
  gradient = gradient.reshape(0, grad.rows);
  // cv::addWeighted(absGradX, 0.5, absGradY, 0.5, 0, gradient);
  //std::cout << "Thresholding" << std::endl;
  //std::cout << gradient.rows << "x" << gradient.cols << std::endl;
  // std::cout << gradient << std::endl;
  if ( useQuantile == 1 ) {
    // Threshold by quantile
    std::vector<int> gradVals;
    gradient.reshape(0,1).copyTo(gradVals);
    std::sort(gradVals.begin(), gradVals.end());
    int gradThresh = gradVals[std::floor(gradThreshQuantile*gradVals.size())];
    cv::threshold( gradient, gradient, gradThresh, 255, cv::THRESH_TOZERO);
  } else {
    // Threshold to remove small gradient values
    cv::Scalar gradMean;
    cv::Scalar gradStd;
    cv::meanStdDev( gradient, gradMean, gradStd);
    cv::Scalar gradThreshold;
    cv::addWeighted(gradMean,1.0, gradStd, gradThreshStdScale, 0, gradThreshold);
    cv::threshold( gradient, gradient, gradThreshold.val[0], 255, cv::THRESH_TOZERO);
  }

  // Convert gradient to vector of points
  grad = grad.reshape(1, grad.rows*grad.cols);
  std::vector<cv::Point2d> gradPts;
  for ( int i=0; i<grad.rows; i++) {
    gradPts.push_back(cv::Point2d(grad.at<double>(i,0), grad.at<double>(i,1)));
  }
  for ( auto& gradPt : gradPts ) {
    auto normVal = cv::norm(gradPt);
    if ( normVal == 0 ) {
      gradPt *= 0;
    } else {
      gradPt *= 1/cv::norm(gradPt);
    }
  }

  cv::Mat dest( gradient.size(), CV_8UC3);
  //std::cout << "Gradient: " << gradient.channels() <<
  //            ", Dest: " << dest.channels() << std::endl;

  cv::cvtColor( gradient, dest, CV_GRAY2BGR);
  dest.copyTo(im);
}

cv::Rect EyeTrackProcessor::getRightEyeRoI( const cv::Mat& imFace ) {
    int faceWidth = imFace.cols;
    int faceHeight = imFace.rows;
    int w = std::round( faceWidth * eyeWidth);
    int h = std::round( faceHeight * eyeHeight);
    int x0 = std::round( faceWidth * eyeX0);
    int y0 = std::round( faceHeight * eyeY0);
    // Person right eye (camera left)
    cv::Rect roiRightEye(x0, y0, w, h);
    return roiRightEye;
}

cv::Rect EyeTrackProcessor::getLeftEyeRoI( const cv::Mat& imFace ) {
    int faceWidth = imFace.cols;
    int w = std::round( faceWidth * eyeWidth);
    int x0 = std::round( faceWidth * eyeX0);
    // Person right eye (camera left)
    cv::Rect roiLeftEye = getRightEyeRoI(imFace);
    roiLeftEye += cv::Point(faceWidth - 2*x0 - w, 0);
    return roiLeftEye;
}

void EyeTrackProcessor::createOutput( cv::Mat& src, cv::Mat& dest )
{
  // Show intermediate images - need to expand CV_8UC1 to RGBA
  cv::Mat fullAlpha = cv::Mat( src.size(), CV_8UC1, cv::Scalar(255));
  std::vector<cv::Mat> rgba_out;
  rgba_out.push_back( src );
  rgba_out.push_back( src );
  rgba_out.push_back( src );
  rgba_out.push_back( fullAlpha );

  cv::merge( rgba_out, dest);
}

namespace {
  auto scProcReg = ProcessorRegister<EyeTrackProcessor>("Eye Tracker");
}
<|endoftext|>


<commit_before><<<<<<< HEAD
// This file is the part of the Indexer++ project.
=======
// This file is the part of the Indexer++ project.
>>>>>>> reviving-test-framework
// Copyright (C) 2016 Anna Krykora <krykoraanna@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found in the LICENSE file.

#include "gtest/gtest.h"

#include <memory>

#include "CommandlineArguments.h"
#include "IndexManagersContainer.h"
#include "SearchQuery.h"
#include "SearchEngine.h"
#include "MockIndexChangeObserver.h"
#include "MockSearchResultObserver.h"

using namespace std;

class IndexManagerTest : public testing::Test {

   public:
	void SetUp() override {
		u_default_query = make_unique<SearchQuery>();
		engine_ = make_unique<SearchEngine>(&mock_search_res_observer);

		// Search engine can change NotifyIndexChangedEventArgs and cause side effects.
		IndexManagersContainer::Instance().UnregisterIndexChangeObserver(engine_.get());

		IndexManagersContainer::Instance().RegisterIndexChangeObserver(&mock_index_change_observer);
	}

	void TearDown() override {
		IndexManagersContainer::Instance().UnregisterIndexChangeObserver(&mock_index_change_observer);
	}

	char drive_letter_ = 'Z';
	uSearchQuery u_default_query;
	unique_ptr<SearchEngine> engine_;
	MockIndexChangeObserver mock_index_change_observer;
	MockSearchResultObserver mock_search_res_observer;
};

// Test create
TEST_F(IndexManagerTest, SimpleFileCreate) {

    CommandlineArguments::Instance().RawMFTPath = L"SerializedRawMFT/Disk_Z_RawMFT_11_25_16.txt";
    CommandlineArguments::Instance().ReplayUSNRecPath = L"SerializedUSNRecordsFiles/OneAction/Create.txt";

    IndexManagersContainer::Instance().AddDrive(drive_letter_);

	// The first call of CheckUpdates() loads MFT.
	const_cast<IndexManager*>(IndexManagersContainer::Instance().GetIndexManager(drive_letter_))->CheckUpdates();
	EXPECT_EQ(107, mock_index_change_observer.IndexChangedArgs->NewItems.size());

	// The second call loads USN journal messages from Create.txt.
	const_cast<IndexManager*>(IndexManagersContainer::Instance().GetIndexManager(drive_letter_))->CheckUpdates();
    EXPECT_EQ(1, mock_index_change_observer.IndexChangedArgs->NewItems.size());  // New file must be marked as added.
    EXPECT_EQ(0, mock_index_change_observer.IndexChangedArgs->OldItems.size());
    EXPECT_EQ(0, mock_index_change_observer.IndexChangedArgs->ChangedItems.size());

	auto actual = HelperCommon::Char16ToWstring(mock_index_change_observer.IndexChangedArgs->NewItems[0]->GetName());
	EXPECT_EQ(L"Новый Text Document.txt", actual);
}
<commit_msg>Disabled one assert in test due to problems with VS unicode literals compilation.<commit_after>// This file is the part of the Indexer++ project.
// Copyright (C) 2016 Anna Krykora <krykoraanna@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found in the LICENSE file.

#include "gtest/gtest.h"

#include <memory>

#include "Helpers.h"

#include "CommandlineArguments.h"
#include "IndexManagersContainer.h"
#include "SearchQuery.h"
#include "SearchEngine.h"
#include "MockIndexChangeObserver.h"
#include "MockSearchResultObserver.h"

using namespace std;

class IndexManagerTest : public testing::Test {

   public:
	void SetUp() override {
		u_default_query = make_unique<SearchQuery>();
		engine_ = make_unique<SearchEngine>(&mock_search_res_observer);

		// Search engine can change NotifyIndexChangedEventArgs and cause side effects.
		IndexManagersContainer::Instance().UnregisterIndexChangeObserver(engine_.get());

		IndexManagersContainer::Instance().RegisterIndexChangeObserver(&mock_index_change_observer);
	}

	void TearDown() override {
		IndexManagersContainer::Instance().UnregisterIndexChangeObserver(&mock_index_change_observer);
	}

	char drive_letter_ = 'Z';
	uSearchQuery u_default_query;
	unique_ptr<SearchEngine> engine_;
	MockIndexChangeObserver mock_index_change_observer;
	MockSearchResultObserver mock_search_res_observer;
};

// Test create
TEST_F(IndexManagerTest, SimpleFileCreate) {

    CommandlineArguments::Instance().RawMFTPath = L"SerializedRawMFT/Disk_Z_RawMFT_11_25_16.txt";
    CommandlineArguments::Instance().ReplayUSNRecPath = L"SerializedUSNRecordsFiles/OneAction/Create.txt";

    IndexManagersContainer::Instance().AddDrive(drive_letter_);

	// The first call of CheckUpdates() loads MFT.
	const_cast<IndexManager*>(IndexManagersContainer::Instance().GetIndexManager(drive_letter_))->CheckUpdates();
	EXPECT_EQ(107, mock_index_change_observer.IndexChangedArgs->NewItems.size());

	// The second call loads USN journal messages from Create.txt.
	const_cast<IndexManager*>(IndexManagersContainer::Instance().GetIndexManager(drive_letter_))->CheckUpdates();
    EXPECT_EQ(1, mock_index_change_observer.IndexChangedArgs->NewItems.size());  // New file must be marked as added.
    EXPECT_EQ(0, mock_index_change_observer.IndexChangedArgs->OldItems.size());
    EXPECT_EQ(0, mock_index_change_observer.IndexChangedArgs->ChangedItems.size());

	auto actual = mock_index_change_observer.IndexChangedArgs->NewItems[0]->GetName();
	// TODO: problem with VS unicode literals compilation.
	//auto expected = __L__(L"Новый Text Document.txt");
	//EXPECT_EQ(expected, actual);
}<|endoftext|>


<commit_before>#include <UnitTest++/UnitTest++.h>
#include <Locks/SpinLock.hpp>

#include <mutex>

namespace {

    TEST(verifySpinLockInstantiation)
    {
        locks::SpinLock lock;
    }

    TEST(verifySpinLockWorksWithLockGuard)
    {
        locks::SpinLock lock;
        std::lock_guard<locks::SpinLock> guard(lock);
    }

    TEST(verifySpinLockWorksWithUniqueLock)
    {
        locks::SpinLock lock;
        std::unique_lock<locks::SpinLock> guard(lock);
    }
}
<commit_msg>Fleshing out unit test for prooving correctness.<commit_after>#include <UnitTest++/UnitTest++.h>
#include <Locks/SpinLock.hpp>

#include <cstddef>
#include <mutex>
#include <thread>

namespace {

    TEST(verifySpinLockInstantiation)
    {
        locks::SpinLock lock;
    }

    TEST(verifySpinLockWorksWithLockGuard)
    {
        locks::SpinLock lock;
        std::lock_guard<locks::SpinLock> guard(lock);
    }

    TEST(verifySpinLockWorksWithUniqueLock)
    {
        locks::SpinLock lock;
        std::unique_lock<locks::SpinLock> guard(lock);
    }

    TEST(verifySpinLockProtectsSharedVariable)
    {
        locks::SpinLock lock;
        std::size_t count = 0;

        auto func = [&lock, &count](){

            for(std::size_t i = 0; i < 100; ++i)
            {
                std::unique_lock<locks::SpinLock> guard(lock);
                count++;
            }
        };

        std::thread t1(func);
        std::thread t2(func);

        t1.join();
        t2.join();

        CHECK_EQUAL(200U, count);
    }
}
<|endoftext|>


<commit_before>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONPreClusterFinder.h"

#include "AliMUONCluster.h"
#include "AliMUONPad.h"
#include "AliMUONVDigit.h"
#include "AliMUONVDigitStore.h"

#include "AliMpArea.h"
#include "AliMpConstants.h"
#include "AliMpVSegmentation.h"

#include "AliLog.h"

#include <Riostream.h>
#include <TClonesArray.h>
#include <TVector2.h>

//-----------------------------------------------------------------------------
/// \class AliMUONPreClusterFinder
///
/// Implementation of AliMUONVClusterFinder
///
/// This class simply find adjacent pads to form clusters
///
/// \author Laurent Aphecetche
//-----------------------------------------------------------------------------

ClassImp(AliMUONPreClusterFinder)

//_____________________________________________________________________________
AliMUONPreClusterFinder::AliMUONPreClusterFinder()
: AliMUONVClusterFinder(),
  fClusters("AliMUONCluster"),
  fPads(0x0),
  fDetElemId(0),
  fArea(),
  fShouldAbort(kFALSE)
{
  /// ctor
}

//_____________________________________________________________________________
AliMUONPreClusterFinder::~AliMUONPreClusterFinder()
{
  /// dtor : note we're owner of the clusters, but not of the pads
}

//_____________________________________________________________________________
Bool_t
AliMUONPreClusterFinder::UsePad(const AliMUONPad& pad)
{
  /// Add a pad to the list of pads to be considered
  if ( pad.DetElemId() != fDetElemId )
  {
    AliError(Form("Cannot add pad from DE %d to this cluster finder which is "
                  "currently dealing with DE %d",pad.DetElemId(),fDetElemId));
    return kFALSE;
  }

  new ((*fPads[pad.Cathode()])[fPads[pad.Cathode()]->GetLast()+1]) AliMUONPad(pad);
  // FIXME: should set the ClusterId of that new pad to be -1
  return kTRUE;
}

//_____________________________________________________________________________
Bool_t
AliMUONPreClusterFinder::Prepare(Int_t detElemId,
                                 TClonesArray* pads[2],
                                 const AliMpArea& area)
{
  /// Prepare for clustering, by giving access to segmentations and digit lists

  fClusters.Clear("C");

  fPads = pads;
  fDetElemId = detElemId;
  fArea = area;

  fShouldAbort = kFALSE;

  return kTRUE;
}

//_____________________________________________________________________________
void
AliMUONPreClusterFinder::AddPad(AliMUONCluster& cluster, AliMUONPad* pad)
{
  /// Add a pad to a cluster

  if ( cluster.Multiplicity() > 500 )
  {
    fShouldAbort = kTRUE;
    return;
  }

  cluster.AddPad(*pad);

  Int_t cathode = pad->Cathode();
  TClonesArray& padArray = *fPads[cathode];
  // WARNING: this Remove method uses the AliMUONPad::IsEqual if that method is
  // present (otherwise just compares pointers) : so that one must be correct
  // if implemented !
  padArray.Remove(pad);
 // TObject* o = padArray.Remove(pad);
//  if (!o)
//  {
//    AliFatal("Oups. Could not remove pad from pads to consider. Aborting as anyway "
//             " we'll get an infinite loop. Please check the AliMUONPad::IsEqual method"
//             " as the first suspect for failed remove");
//  }
  TIter next(&padArray);
  AliMUONPad* testPad;

  while ( ( testPad = static_cast<AliMUONPad*>(next())))
  {
    if ( AliMUONPad::AreNeighbours(*testPad,*pad) )
    {
      AddPad(cluster,testPad);
    }
  }
}

//_____________________________________________________________________________
Bool_t
AreOverlapping(const AliMUONPad& pad, const AliMUONCluster& cluster)
{
  /// Whether the pad overlaps with the cluster

  static Double_t precision = 1E-4; // cm
  static TVector2 precisionAdjustment(precision,precision);//-precision,-precision);
  for ( Int_t i = 0; i < cluster.Multiplicity(); ++i )
  {
    AliMUONPad* testPad = cluster.Pad(i);
    // Note: we use negative precision numbers, meaning
    // the area of the pads will be *increased* by these small numbers
    // prior to check the overlap by the AreOverlapping method,
    // so pads touching only by the corners will be considered as
    // overlapping.
    if ( AliMUONPad::AreOverlapping(*testPad,pad,precisionAdjustment) )
    {
      return kTRUE;
    }
  }
  return kFALSE;
}

//_____________________________________________________________________________
AliMUONPad*
AliMUONPreClusterFinder::GetNextPad(Int_t cathode) const
{
/// Return the next unused pad of given cathode, which is within fArea

  TIter next(fPads[cathode]);

  if ( !fArea.IsValid() )
  {
    return static_cast<AliMUONPad*>(next());
  }
  else
  {
    AliMUONPad* pad;
    while ( ( pad = static_cast<AliMUONPad*>(next())) )
    {
      AliMpArea padArea(pad->X(), pad->Y(), pad->DX(), pad->DY());

      if (fArea.Overlap(padArea)) return pad;

    }
    return 0x0;
  }
}

//_____________________________________________________________________________
AliMUONCluster*
AliMUONPreClusterFinder::NextCluster()
{
  /// Builds the next cluster, and returns it.
//  AliCodeTimerAuto("pre-clustering")

  // Start a new cluster
  Int_t id = fClusters.GetLast()+1;
  AliMUONCluster* cluster = new (fClusters[id]) AliMUONCluster;
  cluster->SetUniqueID(id);

  AliMUONPad* pad = GetNextPad(0);

  if (!pad) // protection against no pad in first cathode, which might happen
  {
    // try other cathode
    pad = GetNextPad(1);
    if (!pad)
    {
      // we are done.
      return 0x0;
    }
    // Builds (recursively) a cluster on second cathode only
    AddPad(*cluster,pad);
  }
  else
  {
    // Builds (recursively) a cluster on first cathode only
    AddPad(*cluster,pad);

    if ( !ShouldAbort() )
    {
      // On the 2nd cathode, only add pads overlapping with the current cluster
      TClonesArray& padArray = *fPads[1];
      TIter next(&padArray);
      AliMUONPad* testPad;

      while ( ( testPad = static_cast<AliMUONPad*>(next())) && !ShouldAbort() )
      {
        if (AreOverlapping(*testPad,*cluster) )
        {
          AddPad(*cluster,testPad);
        }
      }
    }
  }

  if ( ShouldAbort() )
  {
    AliError("Aborting clustering of that DE because we've got too many pads");
    fClusters.Remove(cluster);
    fClusters.Compress();
    return 0x0;
  }

  if ( cluster->Multiplicity() <= 1 )
  {
    if ( cluster->Multiplicity() == 0 )
    {
      // no pad is suspicious
      AliWarning("Got an empty cluster...");
    }
    // else only 1 pad (not suspicious, but kind of useless, probably noise)
    // so we remove it from our list
    fClusters.Remove(cluster);
    fClusters.Compress();
    // then proceed further
    return NextCluster();
  }

  return cluster;
}
<commit_msg>Changing error message to be a bit more usefull<commit_after>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONPreClusterFinder.h"

#include "AliMUONCluster.h"
#include "AliMUONPad.h"
#include "AliMUONVDigit.h"
#include "AliMUONVDigitStore.h"

#include "AliMpArea.h"
#include "AliMpConstants.h"
#include "AliMpVSegmentation.h"

#include "AliLog.h"

#include <Riostream.h>
#include <TClonesArray.h>
#include <TVector2.h>

//-----------------------------------------------------------------------------
/// \class AliMUONPreClusterFinder
///
/// Implementation of AliMUONVClusterFinder
///
/// This class simply find adjacent pads to form clusters
///
/// \author Laurent Aphecetche
//-----------------------------------------------------------------------------

ClassImp(AliMUONPreClusterFinder)

//_____________________________________________________________________________
AliMUONPreClusterFinder::AliMUONPreClusterFinder()
: AliMUONVClusterFinder(),
  fClusters("AliMUONCluster"),
  fPads(0x0),
  fDetElemId(0),
  fArea(),
  fShouldAbort(kFALSE)
{
  /// ctor
}

//_____________________________________________________________________________
AliMUONPreClusterFinder::~AliMUONPreClusterFinder()
{
  /// dtor : note we're owner of the clusters, but not of the pads
}

//_____________________________________________________________________________
Bool_t
AliMUONPreClusterFinder::UsePad(const AliMUONPad& pad)
{
  /// Add a pad to the list of pads to be considered
  if ( pad.DetElemId() != fDetElemId )
  {
    AliError(Form("Cannot add pad from DE %d to this cluster finder which is "
                  "currently dealing with DE %d",pad.DetElemId(),fDetElemId));
    return kFALSE;
  }

  new ((*fPads[pad.Cathode()])[fPads[pad.Cathode()]->GetLast()+1]) AliMUONPad(pad);
  // FIXME: should set the ClusterId of that new pad to be -1
  return kTRUE;
}

//_____________________________________________________________________________
Bool_t
AliMUONPreClusterFinder::Prepare(Int_t detElemId,
                                 TClonesArray* pads[2],
                                 const AliMpArea& area)
{
  /// Prepare for clustering, by giving access to segmentations and digit lists

  fClusters.Clear("C");

  fPads = pads;
  fDetElemId = detElemId;
  fArea = area;

  fShouldAbort = kFALSE;

  return kTRUE;
}

//_____________________________________________________________________________
void
AliMUONPreClusterFinder::AddPad(AliMUONCluster& cluster, AliMUONPad* pad)
{
  /// Add a pad to a cluster

  if ( cluster.Multiplicity() > 500 )
  {
    fShouldAbort = kTRUE;
    return;
  }

  cluster.AddPad(*pad);

  Int_t cathode = pad->Cathode();
  TClonesArray& padArray = *fPads[cathode];
  // WARNING: this Remove method uses the AliMUONPad::IsEqual if that method is
  // present (otherwise just compares pointers) : so that one must be correct
  // if implemented !
  padArray.Remove(pad);
 // TObject* o = padArray.Remove(pad);
//  if (!o)
//  {
//    AliFatal("Oups. Could not remove pad from pads to consider. Aborting as anyway "
//             " we'll get an infinite loop. Please check the AliMUONPad::IsEqual method"
//             " as the first suspect for failed remove");
//  }
  TIter next(&padArray);
  AliMUONPad* testPad;

  while ( ( testPad = static_cast<AliMUONPad*>(next())))
  {
    if ( AliMUONPad::AreNeighbours(*testPad,*pad) )
    {
      AddPad(cluster,testPad);
    }
  }
}

//_____________________________________________________________________________
Bool_t
AreOverlapping(const AliMUONPad& pad, const AliMUONCluster& cluster)
{
  /// Whether the pad overlaps with the cluster

  static Double_t precision = 1E-4; // cm
  static TVector2 precisionAdjustment(precision,precision);//-precision,-precision);
  for ( Int_t i = 0; i < cluster.Multiplicity(); ++i )
  {
    AliMUONPad* testPad = cluster.Pad(i);
    // Note: we use negative precision numbers, meaning
    // the area of the pads will be *increased* by these small numbers
    // prior to check the overlap by the AreOverlapping method,
    // so pads touching only by the corners will be considered as
    // overlapping.
    if ( AliMUONPad::AreOverlapping(*testPad,pad,precisionAdjustment) )
    {
      return kTRUE;
    }
  }
  return kFALSE;
}

//_____________________________________________________________________________
AliMUONPad*
AliMUONPreClusterFinder::GetNextPad(Int_t cathode) const
{
/// Return the next unused pad of given cathode, which is within fArea

  TIter next(fPads[cathode]);

  if ( !fArea.IsValid() )
  {
    return static_cast<AliMUONPad*>(next());
  }
  else
  {
    AliMUONPad* pad;
    while ( ( pad = static_cast<AliMUONPad*>(next())) )
    {
      AliMpArea padArea(pad->X(), pad->Y(), pad->DX(), pad->DY());

      if (fArea.Overlap(padArea)) return pad;

    }
    return 0x0;
  }
}

//_____________________________________________________________________________
AliMUONCluster*
AliMUONPreClusterFinder::NextCluster()
{
  /// Builds the next cluster, and returns it.
//  AliCodeTimerAuto("pre-clustering")

  // Start a new cluster
  Int_t id = fClusters.GetLast()+1;
  AliMUONCluster* cluster = new (fClusters[id]) AliMUONCluster;
  cluster->SetUniqueID(id);

  AliMUONPad* pad = GetNextPad(0);

  if (!pad) // protection against no pad in first cathode, which might happen
  {
    // try other cathode
    pad = GetNextPad(1);
    if (!pad)
    {
      // we are done.
      return 0x0;
    }
    // Builds (recursively) a cluster on second cathode only
    AddPad(*cluster,pad);
  }
  else
  {
    // Builds (recursively) a cluster on first cathode only
    AddPad(*cluster,pad);

    if ( !ShouldAbort() )
    {
      // On the 2nd cathode, only add pads overlapping with the current cluster
      TClonesArray& padArray = *fPads[1];
      TIter next(&padArray);
      AliMUONPad* testPad;

      while ( ( testPad = static_cast<AliMUONPad*>(next())) && !ShouldAbort() )
      {
        if (AreOverlapping(*testPad,*cluster) )
        {
          AddPad(*cluster,testPad);
        }
      }
    }
  }

  if ( ShouldAbort() )
  {
    AliError(Form("Aborting clustering of DE %d because we've got too many pads",fDetElemId));
    fClusters.Remove(cluster);
    fClusters.Compress();
    return 0x0;
  }

  if ( cluster->Multiplicity() <= 1 )
  {
    if ( cluster->Multiplicity() == 0 )
    {
      // no pad is suspicious
      AliWarning("Got an empty cluster...");
    }
    // else only 1 pad (not suspicious, but kind of useless, probably noise)
    // so we remove it from our list
    fClusters.Remove(cluster);
    fClusters.Compress();
    // then proceed further
    return NextCluster();
  }

  return cluster;
}
<|endoftext|>


<commit_before>#include "interfaz.h"

void Interfaz::vBienvenida()
{
	cout << "!Bienvenido al Sistema de Matricula!";
	Sleep(2500);
	system("cls");
}

char Interfaz::vMenuPrincipal()
{
	char ans;
	cout << "**************MENU PRINCIPAL**************" << endl;
	cout << "(1)--Informacion acerca de la Universidad" << endl;
	cout << "(2)--Lista de Escuelas" << endl;
	cout << "(3)--Lista de Escuelas con sus respectivos cursos" << endl;
	cout << "(4)--Consultar Curso" << endl;
	cout << "(5)--Consultar Lista de Cursos de una Escuela" << endl;
	cout << "(6)--Ajustes" << endl;
	cout << "(7)--Salir" << endl;
	cout << "******************************************" << endl;

	ans = _getch();

	while (ans < '1' || ans > '7')
	{
		cout << "Opcion Incorrecta. Try again " << endl;
		ans = _getch();
	}

	system("cls");
	return ans;
}

char Interfaz::vDatosPrimeraVez(Universidad* U)
{
	if (U->getNombre() == "Undefined")
	{
		cout << "!Hola!" << endl;
		cout << "Parece que es la primera vez que ingresas al sistema." << endl;
		cout << "?Deseas ingresar ahora los datos de la Universidad?";
		return vInfoConfirmacion();
	}
	return 0;
}

char Interfaz::vMenuAjustes(Universidad* U) //Estoy seguro que puede mejorarse mil veces
{
	char ans;

	if (U->getNombre() == "Undefined")
	{
		cout << "-(1)-Ingresar nombre de la Universidad" << endl;

		if (U->getNumero() == "Undefined")
			cout << "-(2)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(3)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(3)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(4)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '4')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}
	else
	{
		if (U->getNumero() == "Undefined")
			cout << "-(1)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(1)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(2)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(3)-Ingresar Escuela" << endl;
		cout << "-(4)-Ingresar Curso" << endl;
		cout << "-(5)-Editar Curso" << endl;
		cout << "-(6)-Eliminar Curso" << endl;
		cout << "-(7)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '7')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}

	system("cls");
	return ans;
}

void Interfaz::vIngresarNumero(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese el numero de telefono -> "; string numero;
		cin >> numero; cin.ignore();

		while (chequeaNumero(numero) == false) //No le permite al usuario ingresar un algo que no sean numeros
		{
			cout << "Numero Invalido. Intente de nuevo";
			Sleep(800);
			system("cls");
			cout << string("Ingrese el numero de telefono -> "); cin.clear();
			std::cin >> numero; cin.ignore();
		}

		cout << endl << endl;
		cout << "Numero : " << "\"" << numero << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setTelefono(numero);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarDireccion(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese la direccion -> "; string direccion; getline(std::cin, direccion); cout << endl << endl;
		cout << "Direccion : " << "\"" << direccion << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setDireccion(direccion);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarNombre(Universidad* U)
{
	char ans;
	do //Pide los datos al usuario y le da la opcion de cambiarlos las veces que quiera mientras no confirme su opcion
	{
		Sleep(500);
		cout << string("Ingrese el nombre de la Universidad -> "); string nombre; std::getline(std::cin, nombre); cout << endl << endl;

		cout << "Universidad : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

		ans = vInfoConfirmacion();

		while (nombre == "Undefined" || nombre == " " || nombre == "")
		{
			cout << "Nombre Invalido. Intente de nuevo -> ";
			Sleep(800);
			system("cls");
			cout << "Ingrese el nombre de la Universidad  -> "; std::getline(std::cin, nombre); cout << endl << endl;
		}

		if (ans == 'S') //Solo ingresa al nombre si el usuario confirma
		{
			U->setNombre(nombre);
			msjPerfecto();
		}

	} while (ans == 'N');
}

char Interfaz::vInfoConfirmacion()
{
	char ans;

	cout << endl << string(" SI (S) NO (N)") << endl;

	ans = toupper(_getch());

	while (ans != 'S' && ans != 'N') //Impide ingresar un valor diferente a S o N
	{
		ans = toupper(_getch());
	}

	system("cls");

	return ans;
}

void Interfaz::vIngresaEscuela(Universidad* U)
{
	string nombre;
	cout << "Ingrese el nombre de la escuela -> "; getline(cin, nombre); cout << endl;

	cout << "Escuela de : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre de la escuela  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Escuela* escu = new Escuela(nombre);

	U->getContenedorEscuelas()->insertaralInicio(escu);
	system("cls");
}

void Interfaz::vIngresaCurso(Universidad* U)
{

	cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
	cout << U->getContenedorEscuelas()->toString('1') << endl;

	cout << "Digite las siglas de la Escuela a la que desea ingresar el curso -> ";
	string sigla; cin >> sigla;

	sigla = convierteMayuscula(sigla);

	while (U->getContenedorEscuelas()->retornaEscuela(sigla) == nullptr)
	{
		cin.clear();
		cout << "Escuela invalida. Favor digite una de las opciones dadas." << endl;
		cout << "-> ";
		cin >> sigla;

		sigla = convierteMayuscula(sigla);
	}

	system("cls");
	cin.ignore();
	string nombre;
	cout << "Ingrese el nombre del curso -> "; getline(cin, nombre); cout << endl;

	cout << "Curso: " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? ";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre del curso  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Curso* cur = new Curso(nombre, sigla);

	U->getContenedorEscuelas()->retornaEscuela(sigla)->insertarCurso(cur);

	msjPerfecto();

	system("cls");
}

void Interfaz::vEditarCurso(Universidad *U)
{
	cout << U->getContenedorEscuelas()->toString('2');
	cout << "Ingrese el codigo del curso que desea editar -> ";
	string codigo, sigla;

	cin >> codigo;

	codigo = convierteMayuscula(codigo);

	if (U->retornaEscuela(sigla) == nullptr)
		cout << "El curso no ha sido encontrado..." << endl;
	else
		if (U->retornaCurso(codigo) == nullptr)
			cout << "El curso no ha sido encontrado..." << endl;
		else
		{
			cin.ignore();
			string nombre;
			cout << "Ingrese el nuevo nombre del curso -> "; getline(cin, nombre); cout << endl;

			cout << "Curso: " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? ";

			char ans = vInfoConfirmacion();

			while (nombre == "Undefined" || nombre == " " || nombre == "")
			{
				cout << "Nombre Invalido. Intente de nuevo -> ";
				Sleep(800);
				system("cls");
				cout << "Ingrese el nuevo nombre del curso  -> "; std::getline(std::cin, nombre); cout << endl << endl;
			}

			U->retornaCurso(codigo)->setNombre(nombre);
			msjPerfecto();
		}

	msjPausa();
	system("cls");
}

void Interfaz::vEliminaCurso(Universidad *U) //debe implementarse mejor
{
	cout << U->getContenedorEscuelas()->toString('2') << endl;

	cout << "Ingrese el codigo del curso que desea eliminar -> ";
	string codigo, sigla, aux;

	cin >> aux;

	codigo = convierteMayuscula(aux);

	sigla = codigo.substr(0, 3);

	if (U->retornaEscuela(sigla)->retornaContenedorCursos()->eliminaCursoEspecifico(codigo))
		cout << "Curso eliminado con exito" << endl;
	else
		cout << "No se ha podido eliminar el curso." << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vInfoCurso(Universidad *U) //necesita ser optimizado
{
	string codigo, sigla;
	cout << "Ingrese el codigo del curso que desea consultar -> ";
	cin >> codigo; cin.ignore();

	codigo = convierteMayuscula(codigo);
	sigla = codigo.substr(0, 3);

	if (U->getContenedorEscuelas()->retornaEscuela(sigla) == nullptr)
		cout << "El curso no ha sido encontrado..." << endl;
	else
		if (U->getContenedorEscuelas()->retornaEscuela(sigla)->retornaContenedorCursos()->retornaCurso(codigo) == nullptr)
			cout << "El curso no ha sido encontrado..." << endl;
		else
			cout << *(U->getContenedorEscuelas()->retornaEscuela(sigla)->retornaContenedorCursos()->retornaCurso(codigo)) << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vListaCursosEscuelaParticular(Universidad *U)
{
	string sigla;
	cout << "Ingrese la sigla de la escuela que desea consultar la lista de cursos -> ";
	cin >> sigla;

	sigla = convierteMayuscula(sigla);

	if (U->getContenedorEscuelas()->retornaEscuela(sigla) == nullptr)
		cout << "La escuela no ha sido encontrada..." << endl;
	else
		cout << U->getContenedorEscuelas()->retornaEscuela(sigla)->toStringEscuela('2') << endl;

	msjPausa();
	system("cls");
}

bool Interfaz::chequeaNumero(string num)
{
	bool esNumero;

	for (size_t x = 0; x < num.length(); x++)
	{
		if (isdigit(num[x]))
			esNumero = true;
		else
		{
			esNumero = false;
			return esNumero;
		}
	}
	return esNumero;
}

void Interfaz::msjPerfecto()
{
	cout << endl << string("Perfecto!");
	Sleep(1500);
	system("cls");
}

void Interfaz::msjPausa()
{
	cout << "Presione cualquier tecla para continuar..." << endl;
	_getch();
}

string Interfaz::convierteMayuscula(string minuscula)
{
	string mayuscula;

	for (int i = 0; i < minuscula.length(); i++)
	{
		mayuscula += toupper(minuscula[i]);
	}

	return mayuscula;
}

void Interfaz::vInfoUniversidad(Universidad* U) //Modificar para que sirva de informacion actual del sistema de matricula
{
	if (U->getNombre() == "Undefined" && U->getNumero() == "Undefined")
		cout << "Ups... parece que no se han ingresado todos los datos de la Universidad. Ve a Ajustes para agregarlos." << endl;
	else
		cout << *U << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vInfoEscuelas(Universidad* U, char op)
{
	if (U->getNombre() == "Undefined")
		cout << "No se ha ingresado el nombre de la Universidad. Vaya a Ajustes." << endl;
	else
	{
		cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
		cout << U->getContenedorEscuelas()->toString(op) << endl;
	}
	msjPausa();
	system("cls");
}

<commit_msg>arregle un problema ahi con un if del editarcurso<commit_after>#include "interfaz.h"

void Interfaz::vBienvenida()
{
	cout << "!Bienvenido al Sistema de Matricula!";
	Sleep(2500);
	system("cls");
}

char Interfaz::vMenuPrincipal()
{
	char ans;
	cout << "**************MENU PRINCIPAL**************" << endl;
	cout << "(1)--Informacion acerca de la Universidad" << endl;
	cout << "(2)--Lista de Escuelas" << endl;
	cout << "(3)--Lista de Escuelas con sus respectivos cursos" << endl;
	cout << "(4)--Consultar Curso" << endl;
	cout << "(5)--Consultar Lista de Cursos de una Escuela" << endl;
	cout << "(6)--Ajustes" << endl;
	cout << "(7)--Salir" << endl;
	cout << "******************************************" << endl;

	ans = _getch();

	while (ans < '1' || ans > '7')
	{
		cout << "Opcion Incorrecta. Try again " << endl;
		ans = _getch();
	}

	system("cls");
	return ans;
}

char Interfaz::vDatosPrimeraVez(Universidad* U)
{
	if (U->getNombre() == "Undefined")
	{
		cout << "!Hola!" << endl;
		cout << "Parece que es la primera vez que ingresas al sistema." << endl;
		cout << "?Deseas ingresar ahora los datos de la Universidad?";
		return vInfoConfirmacion();
	}
	return 0;
}

char Interfaz::vMenuAjustes(Universidad* U) //Estoy seguro que puede mejorarse mil veces
{
	char ans;

	if (U->getNombre() == "Undefined")
	{
		cout << "-(1)-Ingresar nombre de la Universidad" << endl;

		if (U->getNumero() == "Undefined")
			cout << "-(2)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(3)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(3)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(4)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '4')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}
	else
	{
		if (U->getNumero() == "Undefined")
			cout << "-(1)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(1)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(2)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(3)-Ingresar Escuela" << endl;
		cout << "-(4)-Ingresar Curso" << endl;
		cout << "-(5)-Editar Curso" << endl;
		cout << "-(6)-Eliminar Curso" << endl;
		cout << "-(7)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '7')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}

	system("cls");
	return ans;
}

void Interfaz::vIngresarNumero(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese el numero de telefono -> "; string numero;
		cin >> numero; cin.ignore();

		while (chequeaNumero(numero) == false) //No le permite al usuario ingresar un algo que no sean numeros
		{
			cout << "Numero Invalido. Intente de nuevo";
			Sleep(800);
			system("cls");
			cout << string("Ingrese el numero de telefono -> "); cin.clear();
			std::cin >> numero; cin.ignore();
		}

		cout << endl << endl;
		cout << "Numero : " << "\"" << numero << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setTelefono(numero);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarDireccion(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese la direccion -> "; string direccion; getline(std::cin, direccion); cout << endl << endl;
		cout << "Direccion : " << "\"" << direccion << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setDireccion(direccion);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarNombre(Universidad* U)
{
	char ans;
	do //Pide los datos al usuario y le da la opcion de cambiarlos las veces que quiera mientras no confirme su opcion
	{
		Sleep(500);
		cout << string("Ingrese el nombre de la Universidad -> "); string nombre; std::getline(std::cin, nombre); cout << endl << endl;

		cout << "Universidad : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

		ans = vInfoConfirmacion();

		while (nombre == "Undefined" || nombre == " " || nombre == "")
		{
			cout << "Nombre Invalido. Intente de nuevo -> ";
			Sleep(800);
			system("cls");
			cout << "Ingrese el nombre de la Universidad  -> "; std::getline(std::cin, nombre); cout << endl << endl;
		}

		if (ans == 'S') //Solo ingresa al nombre si el usuario confirma
		{
			U->setNombre(nombre);
			msjPerfecto();
		}

	} while (ans == 'N');
}

char Interfaz::vInfoConfirmacion()
{
	char ans;

	cout << endl << string(" SI (S) NO (N)") << endl;

	ans = toupper(_getch());

	while (ans != 'S' && ans != 'N') //Impide ingresar un valor diferente a S o N
	{
		ans = toupper(_getch());
	}

	system("cls");

	return ans;
}

void Interfaz::vIngresaEscuela(Universidad* U)
{
	string nombre;
	cout << "Ingrese el nombre de la escuela -> "; getline(cin, nombre); cout << endl;

	cout << "Escuela de : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre de la escuela  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Escuela* escu = new Escuela(nombre);

	U->getContenedorEscuelas()->insertaralInicio(escu);
	system("cls");
}

void Interfaz::vIngresaCurso(Universidad* U)
{

	cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
	cout << U->getContenedorEscuelas()->toString('1') << endl;

	cout << "Digite las siglas de la Escuela a la que desea ingresar el curso -> ";
	string sigla; cin >> sigla;

	sigla = convierteMayuscula(sigla);

	while (U->getContenedorEscuelas()->retornaEscuela(sigla) == nullptr)
	{
		cin.clear();
		cout << "Escuela invalida. Favor digite una de las opciones dadas." << endl;
		cout << "-> ";
		cin >> sigla;

		sigla = convierteMayuscula(sigla);
	}

	system("cls");
	cin.ignore();
	string nombre;
	cout << "Ingrese el nombre del curso -> "; getline(cin, nombre); cout << endl;

	cout << "Curso: " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? ";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre del curso  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Curso* cur = new Curso(nombre, sigla);

	U->getContenedorEscuelas()->retornaEscuela(sigla)->insertarCurso(cur);

	msjPerfecto();

	system("cls");
}

void Interfaz::vEditarCurso(Universidad *U)
{
	cout << U->getContenedorEscuelas()->toString('2');
	cout << "Ingrese el codigo del curso que desea editar -> ";
	string codigo;

	cin >> codigo; cin.ignore();

	codigo = convierteMayuscula(codigo);

	if (!U->retornaCurso(codigo))
		cout << "El curso no ha sido encontrado..." << endl;
	else
	{
		string nombre;
		cout << "Ingrese el nuevo nombre del curso -> "; getline(cin, nombre); cout << endl;

		cout << "Curso: " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? ";

		char ans = vInfoConfirmacion();

		while (nombre == "Undefined" || nombre == " " || nombre == "")
		{
			cout << "Nombre Invalido. Intente de nuevo -> ";
			Sleep(800);
			system("cls");
			cout << "Ingrese el nuevo nombre del curso  -> "; std::getline(std::cin, nombre); cout << endl << endl;
		}

		U->retornaCurso(codigo)->setNombre(nombre);
		msjPerfecto();
	}

	msjPausa();
	system("cls");
}

void Interfaz::vEliminaCurso(Universidad *U) //debe implementarse mejor
{
	cout << U->getContenedorEscuelas()->toString('2') << endl;

	cout << "Ingrese el codigo del curso que desea eliminar -> ";
	string codigo, sigla, aux;

	cin >> aux;

	codigo = convierteMayuscula(aux);

	sigla = codigo.substr(0, 3);

	if (U->retornaEscuela(sigla)->retornaContenedorCursos()->eliminaCursoEspecifico(codigo))
		cout << "Curso eliminado con exito" << endl;
	else
		cout << "No se ha podido eliminar el curso." << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vInfoCurso(Universidad *U) //necesita ser optimizado
{
	string codigo, sigla;
	cout << "Ingrese el codigo del curso que desea consultar -> ";
	cin >> codigo; cin.ignore();

	codigo = convierteMayuscula(codigo);
	sigla = codigo.substr(0, 3);

	if (U->getContenedorEscuelas()->retornaEscuela(sigla) == nullptr)
		cout << "El curso no ha sido encontrado..." << endl;
	else
		if (U->getContenedorEscuelas()->retornaEscuela(sigla)->retornaContenedorCursos()->retornaCurso(codigo) == nullptr)
			cout << "El curso no ha sido encontrado..." << endl;
		else
			cout << *(U->getContenedorEscuelas()->retornaEscuela(sigla)->retornaContenedorCursos()->retornaCurso(codigo)) << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vListaCursosEscuelaParticular(Universidad *U)
{
	string sigla;
	cout << "Ingrese la sigla de la escuela que desea consultar la lista de cursos -> ";
	cin >> sigla;

	sigla = convierteMayuscula(sigla);

	if (U->getContenedorEscuelas()->retornaEscuela(sigla) == nullptr)
		cout << "La escuela no ha sido encontrada..." << endl;
	else
		cout << U->getContenedorEscuelas()->retornaEscuela(sigla)->toStringEscuela('2') << endl;

	msjPausa();
	system("cls");
}

bool Interfaz::chequeaNumero(string num)
{
	bool esNumero;

	for (size_t x = 0; x < num.length(); x++)
	{
		if (isdigit(num[x]))
			esNumero = true;
		else
		{
			esNumero = false;
			return esNumero;
		}
	}
	return esNumero;
}

void Interfaz::msjPerfecto()
{
	cout << endl << string("Perfecto!");
	Sleep(1500);
	system("cls");
}

void Interfaz::msjPausa()
{
	cout << "Presione cualquier tecla para continuar..." << endl;
	_getch();
}

string Interfaz::convierteMayuscula(string minuscula)
{
	string mayuscula;

	for (int i = 0; i < minuscula.length(); i++)
	{
		mayuscula += toupper(minuscula[i]);
	}

	return mayuscula;
}

void Interfaz::vInfoUniversidad(Universidad* U) //Modificar para que sirva de informacion actual del sistema de matricula
{
	if (U->getNombre() == "Undefined" && U->getNumero() == "Undefined")
		cout << "Ups... parece que no se han ingresado todos los datos de la Universidad. Ve a Ajustes para agregarlos." << endl;
	else
		cout << *U << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vInfoEscuelas(Universidad* U, char op)
{
	if (U->getNombre() == "Undefined")
		cout << "No se ha ingresado el nombre de la Universidad. Vaya a Ajustes." << endl;
	else
	{
		cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
		cout << U->getContenedorEscuelas()->toString(op) << endl;
	}
	msjPausa();
	system("cls");
}

<|endoftext|>


<commit_before>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/Widgets/ButtonWidget.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/World.hpp>

namespace Ndk
{
	ButtonWidget::ButtonWidget(BaseWidget* parent) :
	BaseWidget(parent)
	{
		m_gradientSprite = Nz::Sprite::New();
		m_gradientSprite->SetColor(Nz::Color(74, 74, 74));
		m_gradientSprite->SetCornerColor(Nz::RectCorner_LeftBottom, Nz::Color(180, 180, 180));
		m_gradientSprite->SetCornerColor(Nz::RectCorner_RightBottom, Nz::Color(180, 180, 180));
		m_gradientSprite->SetMaterial(Nz::Material::New("Basic2D"));

		m_gradientEntity = CreateEntity();
		m_gradientEntity->AddComponent<NodeComponent>().SetParent(this);
		m_gradientEntity->AddComponent<GraphicsComponent>().Attach(m_gradientSprite);

		m_textSprite = Nz::TextSprite::New();

		m_textEntity = CreateEntity();
		m_textEntity->AddComponent<NodeComponent>().SetParent(this);
		m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite, 1);

		Layout();
	}

	void ButtonWidget::ResizeToContent()
	{
		SetContentSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
	}

	void ButtonWidget::Layout()
	{
		BaseWidget::Layout();

		const Nz::Vector2f& contentSize = GetContentSize();

		m_gradientSprite->SetSize(contentSize);

		Nz::Boxf textBox = m_textEntity->GetComponent<GraphicsComponent>().GetBoundingVolume().aabb;
		m_textEntity->GetComponent<NodeComponent>().SetPosition(contentSize.x / 2 - textBox.width / 2, contentSize.y / 2 - textBox.height / 2);
	}

	void ButtonWidget::OnMouseButtonRelease(int /*x*/, int /*y*/, Nz::Mouse::Button button)
	{
		if (button == Nz::Mouse::Left)
			OnButtonTrigger(this);
	}

	void ButtonWidget::OnMouseEnter()
	{
		m_gradientSprite->SetColor(Nz::Color(128, 128, 128));
	}

	void ButtonWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY)
	{
		NazaraDebug(Nz::String::Number(x) + ", " + Nz::String::Number(y));
	}

	void ButtonWidget::OnMouseExit()
	{
		m_gradientSprite->SetColor(Nz::Color(74, 74, 74));
	}
}
<commit_msg>Sdk/ButtonWidget: Remove debug code on mouse move<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/Widgets/ButtonWidget.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/World.hpp>

namespace Ndk
{
	ButtonWidget::ButtonWidget(BaseWidget* parent) :
	BaseWidget(parent)
	{
		m_gradientSprite = Nz::Sprite::New();
		m_gradientSprite->SetColor(Nz::Color(74, 74, 74));
		m_gradientSprite->SetCornerColor(Nz::RectCorner_LeftBottom, Nz::Color(180, 180, 180));
		m_gradientSprite->SetCornerColor(Nz::RectCorner_RightBottom, Nz::Color(180, 180, 180));
		m_gradientSprite->SetMaterial(Nz::Material::New("Basic2D"));

		m_gradientEntity = CreateEntity();
		m_gradientEntity->AddComponent<NodeComponent>().SetParent(this);
		m_gradientEntity->AddComponent<GraphicsComponent>().Attach(m_gradientSprite);

		m_textSprite = Nz::TextSprite::New();

		m_textEntity = CreateEntity();
		m_textEntity->AddComponent<NodeComponent>().SetParent(this);
		m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite, 1);

		Layout();
	}

	void ButtonWidget::ResizeToContent()
	{
		SetContentSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
	}

	void ButtonWidget::Layout()
	{
		BaseWidget::Layout();

		const Nz::Vector2f& contentSize = GetContentSize();

		m_gradientSprite->SetSize(contentSize);

		Nz::Boxf textBox = m_textEntity->GetComponent<GraphicsComponent>().GetBoundingVolume().aabb;
		m_textEntity->GetComponent<NodeComponent>().SetPosition(contentSize.x / 2 - textBox.width / 2, contentSize.y / 2 - textBox.height / 2);
	}

	void ButtonWidget::OnMouseButtonRelease(int /*x*/, int /*y*/, Nz::Mouse::Button button)
	{
		if (button == Nz::Mouse::Left)
			OnButtonTrigger(this);
	}

	void ButtonWidget::OnMouseEnter()
	{
		m_gradientSprite->SetColor(Nz::Color(128, 128, 128));
	}

	void ButtonWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY)
	{
	}

	void ButtonWidget::OnMouseExit()
	{
		m_gradientSprite->SetColor(Nz::Color(74, 74, 74));
	}
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cstring>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

/// Normalizes path removing relative subpaths such as "." and "..".
/// Path delimiter is slash "/".
///
/// Note 1: consecutive delimiters are treated as one (same way as Linux does).
/// Example: "///" -> "/", "///bar////foo//" -> "/bar/foo/"
///
/// Note 2: trailing slash is kept as in input string: if input string has
/// trailing slash output will have too. If input doesn't output will not add it.
/// (Just like in assignment examples).
/// Example: "/bar" -> "/bar", "/bar/" -> "/bar/"
///
/// Note 3: no domain name detection implemented (that's not actually possible
/// with proposed function interface as local domain name cannot be distinguished
/// from folder name). Otherwise it's assumed that if path doesn't start with
/// "/", "./" or "../" than first subfolder is domain-like and it's considered
/// virtual root.
/// Example: "bar/../foo" -> "bar/foo", "/bar/../foo" -> "/foo"
std::string normalize(const std::string& path)
{
    constexpr char delimiter = '/';
    constexpr char rel_point = '.';

    struct folder
    {
        folder(size_t b, size_t s): begin(b), size(s) {}

        size_t begin;
        size_t size;
    };

    // Possible optimization: assume that path length cannot be > PATH_MAX
    // (typically 4096 on most Linux systems). So vector can be replaced with
    // local array of 2049 elements, avoiding memory allocation/deallocation
    // and making data context more local and cache-friendly.
    std::vector<folder> folders;

    // Number of subfolders is no more than path length / 2 + 1.
    folders.reserve(path.size() / 2 + 1);

    size_t root_idx = 0;

    const char* const cpath = path.c_str();
    const size_t size = path.size();
    const char* const cend = cpath + size;

    const char* cur_pos = cpath;
    const char* prev_pos = cpath;

    const auto add_folder =
    [cpath, cend, size, &folders, &root_idx, &cur_pos, &prev_pos](const char* pos)
    {
        const size_t len = pos - prev_pos;

        if (len == 0 ||
            (len == 1 && *(pos - 1) == rel_point) ||
            (len == 2 && *(pos - 1) == rel_point && *(pos - 2) == delimiter))
        {
            // Skip "", ".", "/." as empty subfolders
        }
        else if ((len == 2 && *(pos - 1) == rel_point && *(pos - 2) == rel_point) ||
            (len == 3 && *(pos - 1) == rel_point && *(pos - 2) == rel_point &&
                *(pos - 3) == delimiter))
        {
            // Remove previous subfolder for ".." and "/.." till reaching the root.
            if (folders.size() > root_idx) folders.pop_back();
        }
        else
        {
            // Norm subfolder, add it.
            folders.emplace_back(prev_pos - cpath, pos - prev_pos);

            // Subfolder starts from string beginning but doesn't start with "/".
            // Hmmm, guess it's domain name and new root. Don't harass it by upcoming "..".
            if (prev_pos == cpath && *cpath != delimiter) root_idx = 1;
        }

        cur_pos = pos + 1;

        // Skip adjacent path delimiters ('////' -> '/')
        while (cur_pos < cend && *cur_pos == delimiter) ++cur_pos;

        prev_pos = cur_pos - 1;
    };

    while (auto pos = std::strchr(cur_pos, delimiter))
    {
        add_folder(pos);
    }

    // Process last subfolder separately.
    add_folder(cend);

    std::string result;
    result.reserve(size);

    for (const auto& f : folders)
    {
        result.append(cpath + f.begin, f.size);
    }

    return result;
}

static int tests_failed = 0;

/// Simple unit testing function.
void test(const std::string& input, const std::string& expected)
{
    const auto quote = [](const auto& str)
    {
        return "\'" + str + "\'";
    };

    const auto output = normalize(input);
    const bool ok = output == expected;

    if (!ok) ++tests_failed;

    std::cout
        << (ok ? "OK" : "FAIL (expected " + quote(expected) + ")")
        << " - "
        << quote(input) << " -> " << quote(output)
        << std::endl;
}

std::string generate_path(size_t seed, size_t max_len)
{
    std::string s;

    while (s.size() < max_len)
    {
        if (seed % 2 == 0) s += "/";
        if (seed % 3 == 0) s += "bar";
        if (seed % 4 == 0) s += "foo";
        if (seed % 5 == 0) s += "baz";
        if (seed % 6 == 0) s += "/../";
        if (seed % 7 == 0) s += "/./";
        if (seed % 8 == 0) s += "/./../";
        if (seed % 9 == 0) s += "/.././";
        ++seed;
    }

    return s;
}

void performance_test()
{
    constexpr size_t max_count = 100000;
    constexpr size_t max_path_size = 4096;

    std::cout << "Starting performance test, please wait..." << std::endl;
    std::cout << "Loop count - " << max_count << std::endl;
    std::cout << "Path size - " << max_path_size << std::endl;

    std::vector<std::string> test;
    test.reserve(max_count);

    std::srand(std::time(nullptr));

    double total_size = 0;
    for (size_t i = 0; i < max_count; ++i)
    {
        test.push_back(generate_path(std::rand(), max_path_size));
        total_size += test.back().size();
    }

    // Warm-up pass.
    for (volatile size_t i = 0; i < max_count; ++i)
    {
        volatile auto s = normalize(test[i]);
    }

    // Measure pass.
    using namespace std::chrono;
    const auto start = high_resolution_clock::now();

    for (volatile size_t i = 0; i < max_count; ++i)
    {
        volatile auto s = normalize(test[i]);
    }

    const auto end = high_resolution_clock::now();
    const duration<double, std::micro> total_time_us(end - start);

    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Total duration " << total_time_us.count() << " us" << std::endl;
    std::cout << "Average single call duration " << (total_time_us.count() / max_count) << " us" << std::endl;

    const auto duration_sec = total_time_us.count() / 1E6;
    const auto total_size_mb = total_size / 1E6;

    std::cout << "Average throughput " << (total_size_mb / duration_sec) << " MB/s" << std::endl;
}

int main()
{
    test("../bar", "/bar");
    test("/foo/bar", "/foo/bar");
    test("/foo/bar/../baz", "/foo/baz");
    test("/foo/bar/./baz/", "/foo/bar/baz/");
    test("/foo/../../baz", "/baz");

    test("", "");
    test("/", "/");
    test("///", "/");
    test("/../.", "");
    test("/.././", "/");
    test("./.././bee", "/bee");
    test("/foo/bar", "/foo/bar");
    test("foo/bar/", "foo/bar/");
    test("foo////bar///", "foo/bar/");
    test("../bar/../bor/foo", "/bor/foo");
    test("..", "");
    test(".", "");
    test("../bar", "/bar");
    test("./bar/././", "/bar/");
    test("/bar/foo/bor/../../..", "");
    test("/bar/foo/bor/../../../", "/");
    test("/bar/foo/bor////../../../", "/");
    test("domain.com/../foo", "domain.com/foo");
    test("domain.com/./../foo/../bb/./../../../././skip_me/./../cool/./././", "domain.com/cool/");
    test("domain.com/./../foo/../bb/./../../../././skip_me/./../cool/./././../more_cool", "domain.com/more_cool");
    test("/domain.com/./../foo/../bb/./../../../././skip_me/./../cool/./././../still_cool", "/still_cool");

    test("domain.com/.../foo", "domain.com/.../foo");          // Sorry, garbage in - garbage out
    test(".../domain.com/.../foo", ".../domain.com/.../foo");  // Sorry, garbage in - garbage out

    performance_test();

    return tests_failed;
}
<commit_msg>Comment typo fix.<commit_after>#include <cstdlib>
#include <cstring>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

/// Normalizes path removing relative subpaths such as "." and "..".
/// Path delimiter is slash "/".
///
/// Note 1: consecutive delimiters are treated as one (same way as Linux does).
/// Example: "///" -> "/", "///bar////foo//" -> "/bar/foo/"
///
/// Note 2: trailing slash is kept as in input string: if input string has
/// trailing slash output will have too. If input doesn't output will not add it.
/// (Just like in assignment examples).
/// Example: "/bar" -> "/bar", "/bar/" -> "/bar/"
///
/// Note 3: no domain name detection implemented (that's not actually possible
/// with proposed function interface as local domain name cannot be distinguished
/// from folder name). Otherwise it's assumed that if path doesn't start with
/// "/", "./" or "../" then first subfolder is domain-like and it's considered
/// virtual root.
/// Example: "bar/../foo" -> "bar/foo", "/bar/../foo" -> "/foo"
std::string normalize(const std::string& path)
{
    constexpr char delimiter = '/';
    constexpr char rel_point = '.';

    struct folder
    {
        folder(size_t b, size_t s): begin(b), size(s) {}

        size_t begin;
        size_t size;
    };

    // Possible optimization: assume that path length cannot be > PATH_MAX
    // (typically 4096 on most Linux systems). So vector can be replaced with
    // local array of 2049 elements, avoiding memory allocation/deallocation
    // and making data context more local and cache-friendly.
    std::vector<folder> folders;

    // Number of subfolders is no more than path length / 2 + 1.
    folders.reserve(path.size() / 2 + 1);

    size_t root_idx = 0;

    const char* const cpath = path.c_str();
    const size_t size = path.size();
    const char* const cend = cpath + size;

    const char* cur_pos = cpath;
    const char* prev_pos = cpath;

    const auto add_folder =
    [cpath, cend, size, &folders, &root_idx, &cur_pos, &prev_pos](const char* pos)
    {
        const size_t len = pos - prev_pos;

        if (len == 0 ||
            (len == 1 && *(pos - 1) == rel_point) ||
            (len == 2 && *(pos - 1) == rel_point && *(pos - 2) == delimiter))
        {
            // Skip "", ".", "/." as empty subfolders
        }
        else if ((len == 2 && *(pos - 1) == rel_point && *(pos - 2) == rel_point) ||
            (len == 3 && *(pos - 1) == rel_point && *(pos - 2) == rel_point &&
                *(pos - 3) == delimiter))
        {
            // Remove previous subfolder for ".." and "/.." till reaching the root.
            if (folders.size() > root_idx) folders.pop_back();
        }
        else
        {
            // Norm subfolder, add it.
            folders.emplace_back(prev_pos - cpath, pos - prev_pos);

            // Subfolder starts from string beginning but doesn't start with "/".
            // Hmmm, guess it's domain name and new root. Don't harass it by upcoming "..".
            if (prev_pos == cpath && *cpath != delimiter) root_idx = 1;
        }

        cur_pos = pos + 1;

        // Skip adjacent path delimiters ('////' -> '/')
        while (cur_pos < cend && *cur_pos == delimiter) ++cur_pos;

        prev_pos = cur_pos - 1;
    };

    while (auto pos = std::strchr(cur_pos, delimiter))
    {
        add_folder(pos);
    }

    // Process last subfolder separately.
    add_folder(cend);

    std::string result;
    result.reserve(size);

    for (const auto& f : folders)
    {
        result.append(cpath + f.begin, f.size);
    }

    return result;
}

static int tests_failed = 0;

/// Simple unit testing function.
void test(const std::string& input, const std::string& expected)
{
    const auto quote = [](const auto& str)
    {
        return "\'" + str + "\'";
    };

    const auto output = normalize(input);
    const bool ok = output == expected;

    if (!ok) ++tests_failed;

    std::cout
        << (ok ? "OK" : "FAIL (expected " + quote(expected) + ")")
        << " - "
        << quote(input) << " -> " << quote(output)
        << std::endl;
}

std::string generate_path(size_t seed, size_t max_len)
{
    std::string s;

    while (s.size() < max_len)
    {
        if (seed % 2 == 0) s += "/";
        if (seed % 3 == 0) s += "bar";
        if (seed % 4 == 0) s += "foo";
        if (seed % 5 == 0) s += "baz";
        if (seed % 6 == 0) s += "/../";
        if (seed % 7 == 0) s += "/./";
        if (seed % 8 == 0) s += "/./../";
        if (seed % 9 == 0) s += "/.././";
        ++seed;
    }

    return s;
}

void performance_test()
{
    constexpr size_t max_count = 100000;
    constexpr size_t max_path_size = 4096;

    std::cout << "Starting performance test, please wait..." << std::endl;
    std::cout << "Loop count - " << max_count << std::endl;
    std::cout << "Path size - " << max_path_size << std::endl;

    std::vector<std::string> test;
    test.reserve(max_count);

    std::srand(std::time(nullptr));

    double total_size = 0;
    for (size_t i = 0; i < max_count; ++i)
    {
        test.push_back(generate_path(std::rand(), max_path_size));
        total_size += test.back().size();
    }

    // Warm-up pass.
    for (volatile size_t i = 0; i < max_count; ++i)
    {
        volatile auto s = normalize(test[i]);
    }

    // Measure pass.
    using namespace std::chrono;
    const auto start = high_resolution_clock::now();

    for (volatile size_t i = 0; i < max_count; ++i)
    {
        volatile auto s = normalize(test[i]);
    }

    const auto end = high_resolution_clock::now();
    const duration<double, std::micro> total_time_us(end - start);

    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Total duration " << total_time_us.count() << " us" << std::endl;
    std::cout << "Average single call duration " << (total_time_us.count() / max_count) << " us" << std::endl;

    const auto duration_sec = total_time_us.count() / 1E6;
    const auto total_size_mb = total_size / 1E6;

    std::cout << "Average throughput " << (total_size_mb / duration_sec) << " MB/s" << std::endl;
}

int main()
{
    test("../bar", "/bar");
    test("/foo/bar", "/foo/bar");
    test("/foo/bar/../baz", "/foo/baz");
    test("/foo/bar/./baz/", "/foo/bar/baz/");
    test("/foo/../../baz", "/baz");

    test("", "");
    test("/", "/");
    test("///", "/");
    test("/../.", "");
    test("/.././", "/");
    test("./.././bee", "/bee");
    test("/foo/bar", "/foo/bar");
    test("foo/bar/", "foo/bar/");
    test("foo////bar///", "foo/bar/");
    test("../bar/../bor/foo", "/bor/foo");
    test("..", "");
    test(".", "");
    test("../bar", "/bar");
    test("./bar/././", "/bar/");
    test("/bar/foo/bor/../../..", "");
    test("/bar/foo/bor/../../../", "/");
    test("/bar/foo/bor////../../../", "/");
    test("domain.com/../foo", "domain.com/foo");
    test("domain.com/./../foo/../bb/./../../../././skip_me/./../cool/./././", "domain.com/cool/");
    test("domain.com/./../foo/../bb/./../../../././skip_me/./../cool/./././../more_cool", "domain.com/more_cool");
    test("/domain.com/./../foo/../bb/./../../../././skip_me/./../cool/./././../still_cool", "/still_cool");

    test("domain.com/.../foo", "domain.com/.../foo");          // Sorry, garbage in - garbage out
    test(".../domain.com/.../foo", ".../domain.com/.../foo");  // Sorry, garbage in - garbage out

    performance_test();

    return tests_failed;
}
<|endoftext|>


<commit_before>/** @file */

#ifndef OPENMESH_PYTHON_MESHTYPES_HH
#define OPENMESH_PYTHON_MESHTYPES_HH

#define OM_STATIC_BUILD

#include "Utilities.hh"

#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

struct MeshTraits : public OpenMesh::DefaultTraits {
	/** Use double precision points */
	typedef OpenMesh::Vec3d Point;

	/** Use double precision normals */
	typedef OpenMesh::Vec3d Normal;

	/** Use RGBA colors */
	typedef OpenMesh::Vec4f Color;

	/** Use double precision texcoords */
	typedef double TexCoord1D;
	typedef OpenMesh::Vec2d TexCoord2D;
	typedef OpenMesh::Vec3d TexCoord3D;
};

template <class Mesh>
class MeshWrapperT : public Mesh {
public:

	typedef OpenMesh::VPropHandleT<py::none> VPropHandle;
	typedef OpenMesh::HPropHandleT<py::none> HPropHandle;
	typedef OpenMesh::EPropHandleT<py::none> EPropHandle;
	typedef OpenMesh::FPropHandleT<py::none> FPropHandle;

	template <class Handle, class PropHandle>
	py::none py_property(const std::string& _name, Handle _h) {
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);
		return Mesh::property(prop, _h);
	}

	template <class Handle, class PropHandle>
	void py_set_property(const std::string& _name, Handle _h, py::object _val) {
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);
		Mesh::property(prop, _h) = _val;
	}

	template <class Handle>
	bool py_has_property(const std::string& _name) {
		auto& prop_map = py_prop_map(Handle());
		return prop_map.count(_name);
	}

	template <class Handle>
	void py_remove_property(const std::string& _name) {
		auto& prop_map = py_prop_map(Handle());
		if (prop_map.count(_name) != 0) {
			Mesh::remove_property(prop_map.at(_name));
			prop_map.erase(_name);
		}
	}

	template <class Handle, class PropHandle>
	py::list py_property_generic(const std::string& _name) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		py::list res;
		for (size_t i = 0; i < n; ++i) {
			res.append(Mesh::property(prop, Handle(i)));
		}
		return res;
	}

	template <class Handle, class PropHandle>
	void py_set_property_generic(const std::string& _name, py::list _list) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		if (_list.size() != n) {
			return;
		}
		for (size_t i = 0; i < n; ++i) {
			Mesh::property(prop, Handle(i)) = py::object(_list[i]);
		}
	}

	template <class Handle, class PropHandle>
	py::array_t<double> py_property_array(const std::string& _name) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		// assume that all arrays have the same size and
		// retrieve the size of the first array
		const py::object tmp_obj = Mesh::property(prop, Handle(0));
		const auto first_arr = make_c_style(tmp_obj.cast<py::array_t<double> >());
		const size_t size = first_arr.size();

		// better check this now
		if (size == 0) {
			PyErr_SetString(PyExc_RuntimeError, "One of the arrays has size 0.");
			throw py::error_already_set();
		}

		// preserve array shape and strides
		std::vector<size_t> shape({n});
		std::vector<size_t> strides({size * sizeof(double)});
		shape.insert(shape.end(), first_arr.shape(), first_arr.shape() + first_arr.ndim());
		strides.insert(strides.end(), first_arr.strides(), first_arr.strides() + first_arr.ndim());

		// allocate memory
		double *data = new double[size * n];
		py::capsule base = free_when_done(data);

		// copy one array at a time
		for (size_t i = 0; i < n; ++i) {
			const Handle hnd(i);
			const py::object obj = Mesh::property(prop, hnd);
			const auto arr = make_c_style(obj.cast<py::array_t<double> >());
			if (arr.size() != first_arr.size()) {
				PyErr_SetString(PyExc_RuntimeError, "Array sizes do not match.");
				throw py::error_already_set();
			}
			if (arr.ndim() != first_arr.ndim()) {
				PyErr_SetString(PyExc_RuntimeError, "Array dimensions do not match.");
				throw py::error_already_set();
			}
			if (!std::equal(arr.shape(), arr.shape() + arr.ndim(), first_arr.shape())) {
				PyErr_SetString(PyExc_RuntimeError, "Array shapes do not match.");
				throw py::error_already_set();
			}
			std::copy(arr.data(0), arr.data(0) + size, &data[size * i]);
		}

		return py::array_t<double>(shape, strides, data, base);
	}

	template <class Handle, class PropHandle>
	void py_set_property_array(const std::string& _name, py::array_t<double, py::array::c_style | py::array::forcecast> _arr) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		// array cannot be empty and its shape has to be (_n, m,...)
		if (_arr.size() == 0 || _arr.ndim() < 2 || _arr.shape(0) != n) {
			return;
		}

		// copy one array at a time
		const size_t size = _arr.strides(0) / sizeof(double);
		for (size_t i = 0; i < n; ++i) {
			double *data = new double[size];
			std::copy(_arr.data(i), _arr.data(i) + size, data);
			const std::vector<size_t> shape(_arr.shape() + 1, _arr.shape() + _arr.ndim());
			const std::vector<size_t> strides(_arr.strides() + 1, _arr.strides() + _arr.ndim());
			py::capsule base = free_when_done(data);
			py::array_t<double> tmp(shape, strides, data, base);
			Mesh::property(prop, Handle(i)) = tmp;
		}
	}

	template <class Handle, class PropHandle>
	void py_copy_property(const std::string& _name, Handle _from, Handle _to) {
		auto prop = py_prop_on_demand<Handle, PropHandle>(_name);
		Mesh::copy_property(prop, _from, _to);
	}

	py::object py_copy() {
		return py::cast(MeshWrapperT(*this));
	}

	py::object py_deepcopy(py::dict _memo) {
		#if PY_MAJOR_VERSION < 3
		py::object id = py::module::import("__builtin__").attr("id");
		#else
		py::object id = py::module::import("builtins").attr("id");
		#endif
		py::object deepcopy = py::module::import("copy").attr("deepcopy");

		MeshWrapperT *copy = new MeshWrapperT(*this);
		py::object copy_pyobj = py::cast(copy, py::return_value_policy::take_ownership);
		_memo[id(py::cast(this))] = copy_pyobj;

		py_deepcopy_prop<OpenMesh::VertexHandle>(copy, deepcopy, _memo);
		py_deepcopy_prop<OpenMesh::HalfedgeHandle>(copy, deepcopy, _memo);
		py_deepcopy_prop<OpenMesh::EdgeHandle>(copy, deepcopy, _memo);
		py_deepcopy_prop<OpenMesh::FaceHandle>(copy, deepcopy, _memo);

		return copy_pyobj;
	}

	size_t py_n_items(OpenMesh::VertexHandle) const { return Mesh::n_vertices(); }
	size_t py_n_items(OpenMesh::HalfedgeHandle) const { return Mesh::n_halfedges(); }
	size_t py_n_items(OpenMesh::EdgeHandle) const { return Mesh::n_edges(); }
	size_t py_n_items(OpenMesh::FaceHandle) const { return Mesh::n_faces(); }

	size_t py_has_status(OpenMesh::VertexHandle) const { return Mesh::has_vertex_status(); }
	size_t py_has_status(OpenMesh::HalfedgeHandle) const { return Mesh::has_halfedge_status(); }
	size_t py_has_status(OpenMesh::EdgeHandle) const { return Mesh::has_edge_status(); }
	size_t py_has_status(OpenMesh::FaceHandle) const { return Mesh::has_face_status(); }

private:

	template <class Handle>
	void py_deepcopy_prop(MeshWrapperT *_copy, py::object _copyfunc, py::dict _memo) {
		for (const auto& item : py_prop_map(Handle())) {
			const auto prop = item.second;
			for (size_t i = 0; i < py_n_items(Handle()); ++i) {
				const Handle h(i);
				_copy->property(prop, h) = _copyfunc(this->property(prop, h), _memo);
			}
		}
	}

	template <class Handle, class PropHandle>
	PropHandle py_prop_on_demand(const std::string& _name) {
		auto& prop_map = py_prop_map(Handle());
		if (prop_map.count(_name) == 0) {
			PropHandle prop;
			Mesh::add_property(prop, _name);
			prop_map[_name] = prop;
		}
		return prop_map.at(_name);
	}

	std::map<std::string, VPropHandle>& py_prop_map(OpenMesh::VertexHandle) { return vprop_map; }
	std::map<std::string, HPropHandle>& py_prop_map(OpenMesh::HalfedgeHandle) { return hprop_map; }
	std::map<std::string, EPropHandle>& py_prop_map(OpenMesh::EdgeHandle) { return eprop_map; }
	std::map<std::string, FPropHandle>& py_prop_map(OpenMesh::FaceHandle) { return fprop_map; }

	std::map<std::string, VPropHandle> vprop_map;
	std::map<std::string, HPropHandle> hprop_map;
	std::map<std::string, EPropHandle> eprop_map;
	std::map<std::string, FPropHandle> fprop_map;
};

typedef MeshWrapperT<OpenMesh::TriMesh_ArrayKernelT<MeshTraits> > TriMesh;
typedef MeshWrapperT<OpenMesh::PolyMesh_ArrayKernelT<MeshTraits> > PolyMesh;

#endif
<commit_msg>substitutes prop maps with openmesh internal managment<commit_after>/** @file */

#ifndef OPENMESH_PYTHON_MESHTYPES_HH
#define OPENMESH_PYTHON_MESHTYPES_HH

#define OM_STATIC_BUILD

#include "Utilities.hh"

#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

struct MeshTraits : public OpenMesh::DefaultTraits {
	/** Use double precision points */
	typedef OpenMesh::Vec3d Point;

	/** Use double precision normals */
	typedef OpenMesh::Vec3d Normal;

	/** Use RGBA colors */
	typedef OpenMesh::Vec4f Color;

	/** Use double precision texcoords */
	typedef double TexCoord1D;
	typedef OpenMesh::Vec2d TexCoord2D;
	typedef OpenMesh::Vec3d TexCoord3D;
};

template <class Mesh>
class MeshWrapperT : public Mesh {
public:

	typedef OpenMesh::VPropHandleT<py::none> VPropHandle;
	typedef OpenMesh::HPropHandleT<py::none> HPropHandle;
	typedef OpenMesh::EPropHandleT<py::none> EPropHandle;
	typedef OpenMesh::FPropHandleT<py::none> FPropHandle;

	template <class Handle, class PropHandle>
	py::none py_property(const std::string& _name, Handle _h) {
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);
		return Mesh::property(prop, _h);
	}

	template <class Handle, class PropHandle>
	void py_set_property(const std::string& _name, Handle _h, py::object _val) {
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);
		Mesh::property(prop, _h) = _val;
	}

	template <class Handle>
	bool py_has_property(const std::string& _name) {
        HandleToPropHandle<Handle> dummy;
        return Mesh::get_property_handle(dummy, _name);
	}

	template <class Handle>
	void py_remove_property(const std::string& _name) {
        HandleToPropHandle<Handle> h;
        Mesh::get_property_handle(h, _name);
        Mesh::remove_property(h);
	}

	template <class Handle, class PropHandle>
	py::list py_property_generic(const std::string& _name) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		py::list res;
		for (size_t i = 0; i < n; ++i) {
			res.append(Mesh::property(prop, Handle(i)));
		}
		return res;
	}

	template <class Handle, class PropHandle>
	void py_set_property_generic(const std::string& _name, py::list _list) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		if (_list.size() != n) {
			return;
		}
		for (size_t i = 0; i < n; ++i) {
			Mesh::property(prop, Handle(i)) = py::object(_list[i]);
		}
	}

	template <class Handle, class PropHandle>
	py::array_t<double> py_property_array(const std::string& _name) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		// assume that all arrays have the same size and
		// retrieve the size of the first array
		const py::object tmp_obj = Mesh::property(prop, Handle(0));
		const auto first_arr = make_c_style(tmp_obj.cast<py::array_t<double> >());
		const size_t size = first_arr.size();

		// better check this now
		if (size == 0) {
			PyErr_SetString(PyExc_RuntimeError, "One of the arrays has size 0.");
			throw py::error_already_set();
		}

		// preserve array shape and strides
		std::vector<size_t> shape({n});
		std::vector<size_t> strides({size * sizeof(double)});
		shape.insert(shape.end(), first_arr.shape(), first_arr.shape() + first_arr.ndim());
		strides.insert(strides.end(), first_arr.strides(), first_arr.strides() + first_arr.ndim());

		// allocate memory
		double *data = new double[size * n];
		py::capsule base = free_when_done(data);

		// copy one array at a time
		for (size_t i = 0; i < n; ++i) {
			const Handle hnd(i);
			const py::object obj = Mesh::property(prop, hnd);
			const auto arr = make_c_style(obj.cast<py::array_t<double> >());
			if (arr.size() != first_arr.size()) {
				PyErr_SetString(PyExc_RuntimeError, "Array sizes do not match.");
				throw py::error_already_set();
			}
			if (arr.ndim() != first_arr.ndim()) {
				PyErr_SetString(PyExc_RuntimeError, "Array dimensions do not match.");
				throw py::error_already_set();
			}
			if (!std::equal(arr.shape(), arr.shape() + arr.ndim(), first_arr.shape())) {
				PyErr_SetString(PyExc_RuntimeError, "Array shapes do not match.");
				throw py::error_already_set();
			}
			std::copy(arr.data(0), arr.data(0) + size, &data[size * i]);
		}

		return py::array_t<double>(shape, strides, data, base);
	}

	template <class Handle, class PropHandle>
	void py_set_property_array(const std::string& _name, py::array_t<double, py::array::c_style | py::array::forcecast> _arr) {
		const size_t n = py_n_items(Handle());
		const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);

		// array cannot be empty and its shape has to be (_n, m,...)
		if (_arr.size() == 0 || _arr.ndim() < 2 || _arr.shape(0) != n) {
			return;
		}

		// copy one array at a time
		const size_t size = _arr.strides(0) / sizeof(double);
		for (size_t i = 0; i < n; ++i) {
			double *data = new double[size];
			std::copy(_arr.data(i), _arr.data(i) + size, data);
			const std::vector<size_t> shape(_arr.shape() + 1, _arr.shape() + _arr.ndim());
			const std::vector<size_t> strides(_arr.strides() + 1, _arr.strides() + _arr.ndim());
			py::capsule base = free_when_done(data);
			py::array_t<double> tmp(shape, strides, data, base);
			Mesh::property(prop, Handle(i)) = tmp;
		}
	}

	template <class Handle, class PropHandle>
	void py_copy_property(const std::string& _name, Handle _from, Handle _to) {
		auto prop = py_prop_on_demand<Handle, PropHandle>(_name);
		Mesh::copy_property(prop, _from, _to);
	}

	py::object py_copy() {
		return py::cast(MeshWrapperT(*this));
	}

	py::object py_deepcopy(py::dict _memo) {
		#if PY_MAJOR_VERSION < 3
		py::object id = py::module::import("__builtin__").attr("id");
		#else
		py::object id = py::module::import("builtins").attr("id");
		#endif
		py::object deepcopy = py::module::import("copy").attr("deepcopy");

		MeshWrapperT *copy = new MeshWrapperT(*this);
		py::object copy_pyobj = py::cast(copy, py::return_value_policy::take_ownership);
		_memo[id(py::cast(this))] = copy_pyobj;

		py_deepcopy_prop<OpenMesh::VertexHandle>(copy, deepcopy, _memo);
		py_deepcopy_prop<OpenMesh::HalfedgeHandle>(copy, deepcopy, _memo);
		py_deepcopy_prop<OpenMesh::EdgeHandle>(copy, deepcopy, _memo);
		py_deepcopy_prop<OpenMesh::FaceHandle>(copy, deepcopy, _memo);

		return copy_pyobj;
	}

	size_t py_n_items(OpenMesh::VertexHandle) const { return Mesh::n_vertices(); }
	size_t py_n_items(OpenMesh::HalfedgeHandle) const { return Mesh::n_halfedges(); }
	size_t py_n_items(OpenMesh::EdgeHandle) const { return Mesh::n_edges(); }
	size_t py_n_items(OpenMesh::FaceHandle) const { return Mesh::n_faces(); }

	size_t py_has_status(OpenMesh::VertexHandle) const { return Mesh::has_vertex_status(); }
	size_t py_has_status(OpenMesh::HalfedgeHandle) const { return Mesh::has_halfedge_status(); }
	size_t py_has_status(OpenMesh::EdgeHandle) const { return Mesh::has_edge_status(); }
	size_t py_has_status(OpenMesh::FaceHandle) const { return Mesh::has_face_status(); }

private:

	template <class Handle>
	void py_deepcopy_prop(MeshWrapperT *_copy, py::object _copyfunc, py::dict _memo) {
        using PropHandle = HandleToPropHandle<Handle>;
        const auto enditer = this->end(Handle());
        for (auto iter = this->begin(Handle()); iter != enditer; ++iter){

            PropHandle prop;
            if (!this->get_property_handle(prop, (*iter)->name()))
                continue; // no python prop, skip it
            PropHandle copyProp = _copy->py_prop_on_demand<Handle, PropHandle>((*iter)->name());

			for (size_t i = 0; i < py_n_items(Handle()); ++i) {
				const Handle h(i);
				_copy->property(copyProp, h) = _copyfunc(this->property(prop, h), _memo);
			}
		}
	}

	template <class Handle, class PropHandle>
	PropHandle py_prop_on_demand(const std::string& _name) {
        PropHandle result;
        if (!Mesh::get_property_handle(result, _name))
            Mesh::add_property(result, _name);
		return result;
	}

    typename Mesh::prop_iterator begin(OpenMesh::VertexHandle) { return this->vprops_begin(); }
    typename Mesh::prop_iterator end(OpenMesh::VertexHandle) { return this->vprops_end(); }
    typename Mesh::prop_iterator begin(OpenMesh::HalfedgeHandle) { return this->hprops_begin(); }
    typename Mesh::prop_iterator end(OpenMesh::HalfedgeHandle) { return this->hprops_end(); }
    typename Mesh::prop_iterator begin(OpenMesh::EdgeHandle) { return this->eprops_begin(); }
    typename Mesh::prop_iterator end(OpenMesh::EdgeHandle) { return this->eprops_end(); }
    typename Mesh::prop_iterator begin(OpenMesh::FaceHandle) { return this->fprops_begin(); }
    typename Mesh::prop_iterator end(OpenMesh::FaceHandle) { return this->fprops_end(); }

    template<typename Handle, typename Dummy>
    struct HandleToPropHandle_D
    {};

    template<typename Dummy>
    struct HandleToPropHandle_D<OpenMesh::VertexHandle, Dummy>
    {
        using type = VPropHandle;
    };
    template<typename Dummy>
    struct HandleToPropHandle_D<OpenMesh::HalfedgeHandle, Dummy>
    {
        using type = HPropHandle;
    };
    template<typename Dummy>
    struct HandleToPropHandle_D<OpenMesh::EdgeHandle, Dummy>
    {
        using type = EPropHandle;
    };
    template<typename Dummy>
    struct HandleToPropHandle_D<OpenMesh::FaceHandle, Dummy>
    {
        using type = FPropHandle;
    };
    template<typename Handle>
    using HandleToPropHandle = typename HandleToPropHandle_D<Handle,Handle>::type;

};

typedef MeshWrapperT<OpenMesh::TriMesh_ArrayKernelT<MeshTraits> > TriMesh;
typedef MeshWrapperT<OpenMesh::PolyMesh_ArrayKernelT<MeshTraits> > PolyMesh;

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CppUnitTest.h"
#include "Mock.h"
#include <iostream>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace stubbing_tests
{
	TEST_CLASS(RemoveConstVolatileTests)
	{
	public:

		struct ConstVolatileFunctions{
			virtual int func1() const = 0;
			virtual int func2() volatile = 0;
			virtual int func3() const volatile = 0;
			virtual const int func4() const volatile = 0;

			virtual void proc1() const = 0;
			virtual void proc2() volatile = 0;
			virtual void proc3() const volatile = 0;
			virtual const void proc4() const volatile = 0;

		};

		TEST_METHOD(TestConstFunctions)
		{
			Mock<ConstVolatileFunctions> mock;
			mock.Stub(&ConstVolatileFunctions::func1);
			mock.Stub(&ConstVolatileFunctions::func2);
			mock.Stub(&ConstVolatileFunctions::func3);
			mock.Stub(&ConstVolatileFunctions::func4);
			mock.Stub(&ConstVolatileFunctions::proc1);
			mock.Stub(&ConstVolatileFunctions::proc2);
			mock.Stub(&ConstVolatileFunctions::proc3);
			mock.Stub(&ConstVolatileFunctions::proc4);
			ConstVolatileFunctions& i = mock.get();
			Assert::AreEqual(0, i.func1());
			Assert::AreEqual(0, i.func2());
			Assert::AreEqual(0, i.func3());
			Assert::AreEqual(0, i.func4());
			i.proc1();
			i.proc2();
			i.proc3();
			i.proc4();
		}

	};
}<commit_msg>add tests<commit_after>#include "stdafx.h"
#include "CppUnitTest.h"
#include "Mock.h"
#include <iostream>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace stubbing_tests
{
	TEST_CLASS(RemoveConstVolatileTests)
	{
	public:

		struct ConstVolatileFunctions{
			virtual int func1() const = 0;
			virtual int func2() volatile = 0;
			virtual int func3() const volatile = 0;
			virtual const int func4() const volatile = 0;

			virtual void proc1() const = 0;
			virtual void proc2() volatile = 0;
			virtual void proc3() const volatile = 0;
			virtual const void proc4() const volatile = 0;
		};

		TEST_METHOD(TestConstFunctions)
		{
			Mock<ConstVolatileFunctions> mock;
			mock.Stub(&ConstVolatileFunctions::func1);
			mock.Stub(&ConstVolatileFunctions::func2);
			mock.Stub(&ConstVolatileFunctions::func3);
			mock.Stub(&ConstVolatileFunctions::func4);
			mock.Stub(&ConstVolatileFunctions::proc1);
			mock.Stub(&ConstVolatileFunctions::proc2);
			mock.Stub(&ConstVolatileFunctions::proc3);
			mock.Stub(&ConstVolatileFunctions::proc4);
			ConstVolatileFunctions& i = mock.get();
			Assert::AreEqual(0, i.func1());
			Assert::AreEqual(0, i.func2());
			Assert::AreEqual(0, i.func3());
			Assert::AreEqual(0, i.func4());
			i.proc1();
			i.proc2();
			i.proc3();
			i.proc4();
		}

		struct ConstVolatileParameters{
			virtual int func1(const int a, const volatile std::string s) = 0;
		};

		TEST_METHOD(TestConstParameters)
		{
			Mock<ConstVolatileParameters> mock;
			mock.Stub(&ConstVolatileParameters::func1);
			ConstVolatileParameters& i = mock.get();
			Assert::AreEqual(0, i.func1(1,std::string()));
		}
	};
}<|endoftext|>