<commit_before>#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cassert>

#include <kms++/kms++.h>
#include "helpers.h"

using namespace std;

namespace kms
{

struct CrtcPriv
{
	drmModeCrtcPtr drm_crtc;
};

Crtc::Crtc(Card &card, uint32_t id, uint32_t idx)
	:DrmPropObject(card, id, DRM_MODE_OBJECT_CRTC, idx)
{
	m_priv = new CrtcPriv();
	m_priv->drm_crtc = drmModeGetCrtc(this->card().fd(), this->id());
	assert(m_priv->drm_crtc);
}

Crtc::~Crtc()
{
	drmModeFreeCrtc(m_priv->drm_crtc);
	delete m_priv;
}

void Crtc::refresh()
{
	drmModeFreeCrtc(m_priv->drm_crtc);

	m_priv->drm_crtc = drmModeGetCrtc(this->card().fd(), this->id());
	assert(m_priv->drm_crtc);
}

void Crtc::setup()
{
	for (Plane* plane : card().get_planes()) {
		if (plane->supports_crtc(this))
			m_possible_planes.push_back(plane);
	}
}

void Crtc::restore_mode(Connector* conn)
{
	auto c = m_priv->drm_crtc;

	uint32_t conns[] = { conn->id() };

	drmModeSetCrtc(card().fd(), id(), c->buffer_id,
		       c->x, c->y,
		       conns, 1, &c->mode);
}

int Crtc::set_mode(Connector* conn, Framebuffer& fb, const Videomode& mode)
{
	uint32_t conns[] = { conn->id() };
	drmModeModeInfo drmmode = video_mode_to_drm_mode(mode);

	return drmModeSetCrtc(card().fd(), id(), fb.id(),
			      0, 0,
			      conns, 1, &drmmode);
}

int Crtc::disable_mode()
{
	return drmModeSetCrtc(card().fd(), id(), 0, 0, 0, 0, 0, 0);
}

static inline uint32_t conv(float x)
{
	// XXX fix the conversion for fractional part
	return ((uint32_t)x) << 16;
}

int Crtc::set_plane(Plane* plane, Framebuffer& fb,
		    int32_t dst_x, int32_t dst_y, uint32_t dst_w, uint32_t dst_h,
		    float src_x, float src_y, float src_w, float src_h)
{
	return drmModeSetPlane(card().fd(), plane->id(), id(), fb.id(), 0,
			       dst_x, dst_y, dst_w, dst_h,
			       conv(src_x), conv(src_y), conv(src_w), conv(src_h));
}

int Crtc::disable_plane(Plane* plane)
{
	return drmModeSetPlane(card().fd(), plane->id(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}

Plane* Crtc::get_primary_plane()
{
	for (Plane* p : get_possible_planes()) {
		if (p->plane_type() != PlaneType::Primary)
			continue;

		return p;
	}

	throw invalid_argument(string("No primary plane for crtc ") + to_string(id()));
}

int Crtc::page_flip(Framebuffer& fb, void *data)
{
	return drmModePageFlip(card().fd(), id(), fb.id(), DRM_MODE_PAGE_FLIP_EVENT, data);
}

uint32_t Crtc::buffer_id() const
{
	return m_priv->drm_crtc->buffer_id;
}

uint32_t Crtc::x() const
{
	return m_priv->drm_crtc->x;
}

uint32_t Crtc::y() const
{
	return m_priv->drm_crtc->y;
}

uint32_t Crtc::width() const
{
	return m_priv->drm_crtc->width;
}

uint32_t Crtc::height() const
{
	return m_priv->drm_crtc->height;
}

int Crtc::mode_valid() const
{
	return m_priv->drm_crtc->mode_valid;
}

Videomode Crtc::mode() const
{
	return drm_mode_to_video_mode(m_priv->drm_crtc->mode);
}

int Crtc::gamma_size() const
{
	return m_priv->drm_crtc->gamma_size;
}

}
<commit_msg>Return primary plane already associated with the CRTC if it exists<commit_after>#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cassert>

#include <kms++/kms++.h>
#include "helpers.h"

using namespace std;

namespace kms
{

struct CrtcPriv
{
	drmModeCrtcPtr drm_crtc;
};

Crtc::Crtc(Card &card, uint32_t id, uint32_t idx)
	:DrmPropObject(card, id, DRM_MODE_OBJECT_CRTC, idx)
{
	m_priv = new CrtcPriv();
	m_priv->drm_crtc = drmModeGetCrtc(this->card().fd(), this->id());
	assert(m_priv->drm_crtc);
}

Crtc::~Crtc()
{
	drmModeFreeCrtc(m_priv->drm_crtc);
	delete m_priv;
}

void Crtc::refresh()
{
	drmModeFreeCrtc(m_priv->drm_crtc);

	m_priv->drm_crtc = drmModeGetCrtc(this->card().fd(), this->id());
	assert(m_priv->drm_crtc);
}

void Crtc::setup()
{
	for (Plane* plane : card().get_planes()) {
		if (plane->supports_crtc(this))
			m_possible_planes.push_back(plane);
	}
}

void Crtc::restore_mode(Connector* conn)
{
	auto c = m_priv->drm_crtc;

	uint32_t conns[] = { conn->id() };

	drmModeSetCrtc(card().fd(), id(), c->buffer_id,
		       c->x, c->y,
		       conns, 1, &c->mode);
}

int Crtc::set_mode(Connector* conn, Framebuffer& fb, const Videomode& mode)
{
	uint32_t conns[] = { conn->id() };
	drmModeModeInfo drmmode = video_mode_to_drm_mode(mode);

	return drmModeSetCrtc(card().fd(), id(), fb.id(),
			      0, 0,
			      conns, 1, &drmmode);
}

int Crtc::disable_mode()
{
	return drmModeSetCrtc(card().fd(), id(), 0, 0, 0, 0, 0, 0);
}

static inline uint32_t conv(float x)
{
	// XXX fix the conversion for fractional part
	return ((uint32_t)x) << 16;
}

int Crtc::set_plane(Plane* plane, Framebuffer& fb,
		    int32_t dst_x, int32_t dst_y, uint32_t dst_w, uint32_t dst_h,
		    float src_x, float src_y, float src_w, float src_h)
{
	return drmModeSetPlane(card().fd(), plane->id(), id(), fb.id(), 0,
			       dst_x, dst_y, dst_w, dst_h,
			       conv(src_x), conv(src_y), conv(src_w), conv(src_h));
}

int Crtc::disable_plane(Plane* plane)
{
	return drmModeSetPlane(card().fd(), plane->id(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}

Plane* Crtc::get_primary_plane()
{
	Plane *primary = nullptr;

	for (Plane* p : get_possible_planes()) {
		if (p->plane_type() != PlaneType::Primary)
			continue;

		if (p->crtc_id() == id())
			return p;

		primary = p;
	}

	if (primary)
		return primary;

	throw invalid_argument(string("No primary plane for crtc ") + to_string(id()));
}

int Crtc::page_flip(Framebuffer& fb, void *data)
{
	return drmModePageFlip(card().fd(), id(), fb.id(), DRM_MODE_PAGE_FLIP_EVENT, data);
}

uint32_t Crtc::buffer_id() const
{
	return m_priv->drm_crtc->buffer_id;
}

uint32_t Crtc::x() const
{
	return m_priv->drm_crtc->x;
}

uint32_t Crtc::y() const
{
	return m_priv->drm_crtc->y;
}

uint32_t Crtc::width() const
{
	return m_priv->drm_crtc->width;
}

uint32_t Crtc::height() const
{
	return m_priv->drm_crtc->height;
}

int Crtc::mode_valid() const
{
	return m_priv->drm_crtc->mode_valid;
}

Videomode Crtc::mode() const
{
	return drm_mode_to_video_mode(m_priv->drm_crtc->mode);
}

int Crtc::gamma_size() const
{
	return m_priv->drm_crtc->gamma_size;
}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: cellsh.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: nn $ $Date: 2001-07-19 19:36:03 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_CELLSH_HXX
#define SC_CELLSH_HXX

#ifndef _SFX_SHELL_HXX //autogen
#include <sfx2/shell.hxx>
#endif
#include "shellids.hxx"
#ifndef _SFXMODULE_HXX //autogen
#include <sfx2/module.hxx>
#endif

#ifndef _SVDMARK_HXX //autogen
#include <svx/svdmark.hxx>
#endif

#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif

#ifndef SC_FORMATSH_HXX
#include "formatsh.hxx"
#endif

class SvxClipboardFmtItem;
class TransferableDataHelper;
class TransferableClipboardListener;

class ScCellShell: public ScFormatShell
{
private:
    TransferableClipboardListener* pClipEvtLstnr;
    BOOL        bPastePossible;

    void        GetPossibleClipboardFormats( SvxClipboardFmtItem& rFormats );

    DECL_LINK( ClipboardChanged, TransferableDataHelper* );

public:

    TYPEINFO();
    SFX_DECL_INTERFACE(SCID_CELL_SHELL);

                ScCellShell(ScViewData* pData);
    virtual     ~ScCellShell();

    void        Execute(SfxRequest &);
    void        GetState(SfxItemSet &);

    void        ExecuteEdit( SfxRequest& rReq );
    void        ExecuteTrans( SfxRequest& rReq );

    void        GetBlockState( SfxItemSet& rSet );
    void        GetCellState( SfxItemSet& rSet );

    void        ExecuteDB( SfxRequest& rReq );
    void        GetDBState( SfxItemSet& rSet );

    void        ExecImageMap(SfxRequest& rReq);     // ImageMap
    void        GetImageMapState(SfxItemSet& rSet);

    void        GetClipState( SfxItemSet& rSet );
    void        GetHLinkState( SfxItemSet& rSet );

    void        ExecuteCursor( SfxRequest& rReq );
    void        ExecuteCursorSel( SfxRequest& rReq );
    void        ExecutePage( SfxRequest& rReq );
    void        ExecutePageSel( SfxRequest& rReq );
    void        ExecuteMove( SfxRequest& rReq );
    void        GetStateCursor( SfxItemSet& rSet );

};

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.5.926); FILE MERGED 2005/09/05 15:05:08 rt 1.5.926.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cellsh.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 21:14:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_CELLSH_HXX
#define SC_CELLSH_HXX

#ifndef _SFX_SHELL_HXX //autogen
#include <sfx2/shell.hxx>
#endif
#include "shellids.hxx"
#ifndef _SFXMODULE_HXX //autogen
#include <sfx2/module.hxx>
#endif

#ifndef _SVDMARK_HXX //autogen
#include <svx/svdmark.hxx>
#endif

#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif

#ifndef SC_FORMATSH_HXX
#include "formatsh.hxx"
#endif

class SvxClipboardFmtItem;
class TransferableDataHelper;
class TransferableClipboardListener;

class ScCellShell: public ScFormatShell
{
private:
    TransferableClipboardListener* pClipEvtLstnr;
    BOOL        bPastePossible;

    void        GetPossibleClipboardFormats( SvxClipboardFmtItem& rFormats );

    DECL_LINK( ClipboardChanged, TransferableDataHelper* );

public:

    TYPEINFO();
    SFX_DECL_INTERFACE(SCID_CELL_SHELL);

                ScCellShell(ScViewData* pData);
    virtual     ~ScCellShell();

    void        Execute(SfxRequest &);
    void        GetState(SfxItemSet &);

    void        ExecuteEdit( SfxRequest& rReq );
    void        ExecuteTrans( SfxRequest& rReq );

    void        GetBlockState( SfxItemSet& rSet );
    void        GetCellState( SfxItemSet& rSet );

    void        ExecuteDB( SfxRequest& rReq );
    void        GetDBState( SfxItemSet& rSet );

    void        ExecImageMap(SfxRequest& rReq);     // ImageMap
    void        GetImageMapState(SfxItemSet& rSet);

    void        GetClipState( SfxItemSet& rSet );
    void        GetHLinkState( SfxItemSet& rSet );

    void        ExecuteCursor( SfxRequest& rReq );
    void        ExecuteCursorSel( SfxRequest& rReq );
    void        ExecutePage( SfxRequest& rReq );
    void        ExecutePageSel( SfxRequest& rReq );
    void        ExecuteMove( SfxRequest& rReq );
    void        GetStateCursor( SfxItemSet& rSet );

};

#endif
<|endoftext|>


<commit_before>#ifndef __Data_course__
#define __Data_course__

#include "data-general.hpp"
#include "data-major.hpp"
#include "data-department.hpp"
using namespace std;

class Course {
protected:
	string ID;
	int number;
	string title;
	string description;
	char section;

	vector<Major> majors;
	Department* department;
	string concentrations;
	string conversations;
	string professor;

	int half_semester;
	bool pass_fail;
	float credits;
	string location;

	bool lab;
	GenEd* geneds;

	bool days[7];
	float time[7];
public:
	Course(istream &is) {
		if (!is) return;

		string tmpLine;
		getline(is, tmpLine); // remove the extra data of course status

		vector<string> record = split(tmpLine, ',');
		for (vector<string>::iterator i=record.begin(); i != record.end(); ++i)
			*i=removeAllQuotes(*i);

		// Ignore the first column;
		record.at(0);

		// Second column has the course ID,
		//number = stringToInt(record.at(1));
		ID = record.at(1);
		number = parseID(ID);

		// Third column has the section,
		section = record.at(2)[0];

		// Fourth holds the lab boolean,
		if (record.at(3).empty())
			lab = false;
		else
			lab = true;

		// while Fifth contains the title of the course;
		title = record.at(4);

		// Sixth hands over the length (half semester or not)
		// it's actually an int that tells us how many times the course is offered per semester.
		half_semester = stringToInt(record.at(5));

		// Seventh tells us the number of credits,
		credits = stringToFloat(record.at(6));

		// Eighth shows us if it can be taken pass/no-pass,
		if (record.at(7) == "Y")
			pass_fail = true;
		else
			pass_fail = false;

		// while Nine gives us the GEs of the course,
		// GEreqs = record.at(9);

		// and Ten spits out the days and times;
		// Times = record.at(10);

		// Eleven holds the location,
		location = record.at(11);

		// and Twelve knows who teaches.
		professor = record.at(12);
	}

	void parseID(string str) {
		unsigned int foundLoc = str.find('/');
		string tempDept = str.substr(0,str.find(' ')-1);

		if (foundLoc != str.npos) {
			string dept1 = tempDept.substr(0,2);
			department.push_back(Department(dept1));

			string dept2 = tempDept.substr(2,2);
			department.push_back(Department(dept2));
		}
		else {
			department.push_back(Department(tempDept));
		}
	}

	void updateID() {
		string dept;
		for (std::vector<Department>::iterator i = department.begin(); i != department.end(); ++i)
			dept += i->getName();
		ID = dept + tostring(number) + section;
	}
	string getID() {
		return ID;
	}

	ostream& getData(ostream &os) {
		os << ID << section << " ";
		os << title << "/";
		/*for (vector<Instructor>::iterator i = professor.begin(); i != professor.end(); ++i) {
		os << i->name << " ";
		}*/
		return os;
	}
	void display();
};

ostream &operator<<(ostream &os, Course &item) { return item.getData(os); }
void Course::display() { if(this==0) cout << *this << endl; }

#endif

<commit_msg>Update the output of getData<commit_after>#ifndef __Data_course__
#define __Data_course__

#include "data-general.hpp"
#include "data-major.hpp"
#include "data-department.hpp"
using namespace std;

class Course {
protected:
	string ID;
	int number;
	string title;
	string description;
	char section;

	vector<Major> majors;
	Department* department;
	string concentrations;
	string conversations;
	string professor;

	int half_semester;
	bool pass_fail;
	float credits;
	string location;

	bool lab;
	GenEd* geneds;

	bool days[7];
	float time[7];
public:
	Course(istream &is) {
		if (!is) return;

		string tmpLine;
		getline(is, tmpLine); // remove the extra data of course status

		vector<string> record = split(tmpLine, ',');
		for (vector<string>::iterator i=record.begin(); i != record.end(); ++i)
			*i=removeAllQuotes(*i);

		// Ignore the first column;
		record.at(0);

		// Second column has the course ID,
		//number = stringToInt(record.at(1));
		ID = record.at(1);
		number = parseID(ID);

		// Third column has the section,
		section = record.at(2)[0];

		// Fourth holds the lab boolean,
		if (record.at(3).empty())
			lab = false;
		else
			lab = true;

		// while Fifth contains the title of the course;
		title = record.at(4);

		// Sixth hands over the length (half semester or not)
		// it's actually an int that tells us how many times the course is offered per semester.
		half_semester = stringToInt(record.at(5));

		// Seventh tells us the number of credits,
		credits = stringToFloat(record.at(6));

		// Eighth shows us if it can be taken pass/no-pass,
		if (record.at(7) == "Y")
			pass_fail = true;
		else
			pass_fail = false;

		// while Nine gives us the GEs of the course,
		// GEreqs = record.at(9);

		// and Ten spits out the days and times;
		// Times = record.at(10);

		// Eleven holds the location,
		location = record.at(11);

		// and Twelve knows who teaches.
		professor = record.at(12);
	}

	void parseID(string str) {
		unsigned int foundLoc = str.find('/');
		string tempDept = str.substr(0,str.find(' ')-1);

		if (foundLoc != str.npos) {
			string dept1 = tempDept.substr(0,2);
			department.push_back(Department(dept1));

			string dept2 = tempDept.substr(2,2);
			department.push_back(Department(dept2));
		}
		else {
			department.push_back(Department(tempDept));
		}
	}

	void updateID() {
		string dept;
		for (std::vector<Department>::iterator i = department.begin(); i != department.end(); ++i)
			dept += i->getName();
		ID = dept + tostring(number) + section;
	}
	string getID() {
		return ID;
	}

	ostream& getData(ostream &os) {
		os << ID << section << " - ";
		os << title << " | ";
		// os << professor << endl;
		return os;
	}
	void display();
};

ostream &operator<<(ostream &os, Course &item) { return item.getData(os); }
void Course::display() { if(this==0) cout << *this << endl; }

#endif

<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "dirtab.h"

#include <cstdio>
#include <cstdlib>

#include "util.h"

using namespace catalog;

Dirtab::Dirtab() : valid_(true) {}

Dirtab::Dirtab(const std::string &dirtab_path) {
  if (! FileExists(dirtab_path)) {
    LogCvmfs(kLogCatalog, kLogStderr, "Cannot find dirtab at '%s'",
             dirtab_path.c_str());
    valid_ = false;
    return;
  }

  FILE *dirtab_file = fopen(dirtab_path.c_str(), "r");
  if (dirtab_file == NULL) {
    LogCvmfs(kLogCatalog, kLogStderr, "Cannot open dirtab for reading at '%s' "
                                      "(errno: %d)",
             dirtab_path.c_str(), errno);
    valid_ = false;
    return;
  }

  valid_ = Parse(dirtab_file);
  fclose(dirtab_file);
}

bool Dirtab::Parse(const std::string &dirtab) {
  valid_ = true;
  off_t line_offset = 0;
  while (line_offset < static_cast<off_t>(dirtab.size())) {
    std::string line = GetLineMem(dirtab.c_str() + line_offset,
                                  dirtab.size() - line_offset);
    line_offset += line.size() + 1; // +1 == skipped \n
    if (! ParseLine(line)) {
      valid_ = false;
    }
  }
  valid_ = valid_ && CheckRuleValidity();
  return valid_;
}

bool Dirtab::Parse(FILE *dirtab_file) {
  valid_ = true;
  std::string line;
  while (GetLineFile(dirtab_file, &line)) {
    if (! ParseLine(line)) {
      valid_ = false;
    }
  }
  valid_ = valid_ && CheckRuleValidity();
  return valid_;
}

bool Dirtab::ParseLine(const std::string &line) {
        std::string::const_iterator itr  = line.begin();
  const std::string::const_iterator iend = line.end();
  bool negation = false;

  // parse preamble
  SkipWhitespace(itr, iend);
  if (*itr == Dirtab::kCommentMarker) {
    return true;
  } else if (*itr == Dirtab::kNegationMarker) {
    negation = true;
    ++itr;
    SkipWhitespace(itr, iend);
  }

  // extract and parse pathspec
  std::string pathspec_str(itr, iend);
  if (pathspec_str.empty()) {
    return true;
  }
  Pathspec pathspec(pathspec_str);
  if ( !pathspec.IsValid() ||
      (!negation && !pathspec.IsAbsolute())) {
    return false;
  }

  // create a new dirtab rule
  const Rule rule(pathspec, negation);
  AddRule(rule);
  return true;
}

void Dirtab::AddRule(const Rule &rule) {
  if (rule.is_negation) {
    negative_rules_.push_back(rule);
  } else {
    positive_rules_.push_back(rule);
  }
}

bool Dirtab::CheckRuleValidity() const {
  // check if there are contradicting positive and negative rules
        Rules::const_iterator p    = positive_rules_.begin();
  const Rules::const_iterator pend = positive_rules_.end();
  for (; p != pend; ++p) {
    assert (! p->is_negation);
          Rules::const_iterator n    = negative_rules_.begin();
    const Rules::const_iterator nend = negative_rules_.end();
    for (; n != nend; ++n) {
      assert (n->is_negation);
      if (p->pathspec == n->pathspec) {
        return false;
      }
    }
  }

  return true;
}

bool Dirtab::IsMatching(const std::string &path) const {
  // check if path has a positive match
  bool has_positive_match = false;
        Rules::const_iterator p    = positive_rules_.begin();
  const Rules::const_iterator pend = positive_rules_.end();
  for (; p != pend; ++p) {
    assert (! p->is_negation);
    if (p->pathspec.IsMatching(path)) {
      has_positive_match = true;
      break;
    }
  }

  return has_positive_match && ! IsOpposing(path);
}

bool Dirtab::IsOpposing(const std::string &path) const {
        Rules::const_iterator n    = negative_rules_.begin();
  const Rules::const_iterator nend = negative_rules_.end();
  for (; n != nend; ++n) {
    assert (n->is_negation);
    if (n->pathspec.IsMatching(path)) {
      return true;
    }
  }

  return false;
}
<commit_msg>relaxed matching for negative dirtab rules<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "dirtab.h"

#include <cstdio>
#include <cstdlib>

#include "util.h"

using namespace catalog;

Dirtab::Dirtab() : valid_(true) {}

Dirtab::Dirtab(const std::string &dirtab_path) {
  if (! FileExists(dirtab_path)) {
    LogCvmfs(kLogCatalog, kLogStderr, "Cannot find dirtab at '%s'",
             dirtab_path.c_str());
    valid_ = false;
    return;
  }

  FILE *dirtab_file = fopen(dirtab_path.c_str(), "r");
  if (dirtab_file == NULL) {
    LogCvmfs(kLogCatalog, kLogStderr, "Cannot open dirtab for reading at '%s' "
                                      "(errno: %d)",
             dirtab_path.c_str(), errno);
    valid_ = false;
    return;
  }

  valid_ = Parse(dirtab_file);
  fclose(dirtab_file);
}

bool Dirtab::Parse(const std::string &dirtab) {
  valid_ = true;
  off_t line_offset = 0;
  while (line_offset < static_cast<off_t>(dirtab.size())) {
    std::string line = GetLineMem(dirtab.c_str() + line_offset,
                                  dirtab.size() - line_offset);
    line_offset += line.size() + 1; // +1 == skipped \n
    if (! ParseLine(line)) {
      valid_ = false;
    }
  }
  valid_ = valid_ && CheckRuleValidity();
  return valid_;
}

bool Dirtab::Parse(FILE *dirtab_file) {
  valid_ = true;
  std::string line;
  while (GetLineFile(dirtab_file, &line)) {
    if (! ParseLine(line)) {
      valid_ = false;
    }
  }
  valid_ = valid_ && CheckRuleValidity();
  return valid_;
}

bool Dirtab::ParseLine(const std::string &line) {
        std::string::const_iterator itr  = line.begin();
  const std::string::const_iterator iend = line.end();
  bool negation = false;

  // parse preamble
  SkipWhitespace(itr, iend);
  if (*itr == Dirtab::kCommentMarker) {
    return true;
  } else if (*itr == Dirtab::kNegationMarker) {
    negation = true;
    ++itr;
    SkipWhitespace(itr, iend);
  }

  // extract and parse pathspec
  std::string pathspec_str(itr, iend);
  if (pathspec_str.empty()) {
    return true;
  }
  Pathspec pathspec(pathspec_str);
  if ( !pathspec.IsValid() ||
      (!negation && !pathspec.IsAbsolute())) {
    return false;
  }

  // create a new dirtab rule
  const Rule rule(pathspec, negation);
  AddRule(rule);
  return true;
}

void Dirtab::AddRule(const Rule &rule) {
  if (rule.is_negation) {
    negative_rules_.push_back(rule);
  } else {
    positive_rules_.push_back(rule);
  }
}

bool Dirtab::CheckRuleValidity() const {
  // check if there are contradicting positive and negative rules
        Rules::const_iterator p    = positive_rules_.begin();
  const Rules::const_iterator pend = positive_rules_.end();
  for (; p != pend; ++p) {
    assert (! p->is_negation);
          Rules::const_iterator n    = negative_rules_.begin();
    const Rules::const_iterator nend = negative_rules_.end();
    for (; n != nend; ++n) {
      assert (n->is_negation);
      if (p->pathspec == n->pathspec) {
        return false;
      }
    }
  }

  return true;
}

bool Dirtab::IsMatching(const std::string &path) const {
  // check if path has a positive match
  bool has_positive_match = false;
        Rules::const_iterator p    = positive_rules_.begin();
  const Rules::const_iterator pend = positive_rules_.end();
  for (; p != pend; ++p) {
    assert (! p->is_negation);
    if (p->pathspec.IsMatching(path)) {
      has_positive_match = true;
      break;
    }
  }

  return has_positive_match && ! IsOpposing(path);
}

bool Dirtab::IsOpposing(const std::string &path) const {
        Rules::const_iterator n    = negative_rules_.begin();
  const Rules::const_iterator nend = negative_rules_.end();
  for (; n != nend; ++n) {
    assert (n->is_negation);
    if (n->pathspec.IsMatchingRelaxed(path)) {
      return true;
    }
  }

  return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "command.h"
#include "progressbar.h"
#include "memory.h"
#include "image.h"
#include "algo/threaded_loop.h"
#include "math/math.h"
#include "math/median.h"

#include <limits>
#include <vector>

using namespace MR;
using namespace App;

const char* operations[] = {
  "mean",
  "median",
  "sum",
  "product",
  "rms",
  "norm",
  "var",
  "std",
  "min",
  "max",
  "absmax", // Maximum of absolute values
  "magmax", // Value for which the magnitude is the maximum (i.e. preserves signed-ness)
  NULL
};

void usage ()
{
  AUTHOR = "J-Donald Tournier (jdtournier@gmail.com)";

  DESCRIPTION
    + "compute summary statistic on image intensities either across images, "
    "or along a specified axis for a single image. Supported operations are:"

    + "mean, median, sum, product, rms (root-mean-square value), norm (vector 2-norm), var (unbiased variance), "
    "std (unbiased standard deviation), min, max, absmax (maximum absolute value), "
    "magmax (value with maximum absolute value, preserving its sign)."

    + "See also 'mrcalc' to compute per-voxel operations.";

  ARGUMENTS
  + Argument ("input", "the input image(s).").type_image_in ().allow_multiple()
  + Argument ("operation", "the operation to apply, one of: " + join(operations, ", ") + ".").type_choice (operations)
  + Argument ("output", "the output image.").type_image_out ();

  OPTIONS
  + Option ("axis", "perform operation along a specified axis of a single input image")
    + Argument ("index").type_integer (0)

  + DataType::options();
}

typedef float value_type;

class Mean {
  public:
    Mean () : sum (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += val;
        ++count;
      }
    }
    value_type result () const {
      if (!count)
        return NAN;
      return sum / count;
    }
    double sum;
    size_t count;
};

class Median {
  public:
    Median () { }
    void operator() (value_type val) {
      if (!std::isnan (val))
        values.push_back(val);
    }
    value_type result () {
      return Math::median(values);
    }
    std::vector<value_type> values;
};

class Sum {
  public:
    Sum () : sum (0.0) { }
    void operator() (value_type val) {
      if (std::isfinite (val))
        sum += val;
    }
    value_type result () const {
      return sum;
    }
    double sum;
};

class Product {
  public:
    Product () : product (NAN) { }
    void operator() (value_type val) {
      if (std::isfinite (val))
        product = std::isfinite (product) ? product * val : val;
    }
    value_type result () const {
      return product;
    }
    double product;
};

class RMS {
  public:
    RMS() : sum (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += Math::pow2 (val);
        ++count;
      }
    }
    value_type result() const {
      if (!count)
        return NAN;
      return std::sqrt(sum / count);
    }
    double sum;
    size_t count;
};

class NORM2 {
  public:
    NORM2() : sum (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += Math::pow2 (val);
        ++count;
      }
    }
    value_type result() const {
      if (!count)
        return NAN;
      return std::sqrt(sum);
    }
    double sum;
    size_t count;
};

class Var {
  public:
    Var () : sum (0.0), sum_sqr (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += val;
        sum_sqr += Math::pow2 (val);
        ++count;
      }
    }
    value_type result () const {
      if (count < 2)
        return NAN;
      return  (sum_sqr - Math::pow2 (sum) / static_cast<double> (count)) / (static_cast<double> (count) - 1.0);
    }
    double sum, sum_sqr;
    size_t count;
};

class Std : public Var {
  public:
    Std() : Var() { }
    value_type result () const { return std::sqrt (Var::result()); }
};

class Min {
  public:
    Min () : min (std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && val < min)
        min = val;
    }
    value_type result () const { return std::isfinite (min) ? min : NAN; }
    value_type min;
};

class Max {
  public:
    Max () : max (-std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && val > max)
        max = val;
    }
    value_type result () const { return std::isfinite (max) ? max : NAN; }
    value_type max;
};

class AbsMax {
  public:
    AbsMax () : max (-std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && std::abs(val) > max)
        max = std::abs(val);
    }
    value_type result () const { return std::isfinite (max) ? max : NAN; }
    value_type max;
};

class MagMax {
  public:
    MagMax () : max (-std::numeric_limits<value_type>::infinity()) { }
    MagMax (const int i) : max (-std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && (!std::isfinite (max) || std::abs(val) > std::abs (max)))
        max = val;
    }
    value_type result () const { return std::isfinite (max) ? max : NAN; }
    value_type max;
};

template <class Operation>
class AxisKernel {
  public:
    AxisKernel (size_t axis) : axis (axis) { }

    template <class InputImageType, class OutputImageType>
      void operator() (InputImageType& in, OutputImageType& out) {
        Operation op;
        for (auto l = Loop (axis) (in); l; ++l)
          op (in.value());
        out.value() = op.result();
      }
  protected:
    const size_t axis;
};

class ImageKernelBase {
  public:
    virtual void process (Header& image_in) = 0;
    virtual void write_back (Image<value_type>& out) = 0;
};

template <class Operation>
class ImageKernel : public ImageKernelBase {
  protected:
    class InitFunctor {
      public:
        template <class ImageType>
          void operator() (ImageType& out) const { out.value() = Operation(); }
    };
    class ProcessFunctor {
      public:
        template <class ImageType1, class ImageType2>
          void operator() (ImageType1& out, ImageType2& in) const {
            Operation op = out.value();
            op (in.value());
            out.value() = op;
          }
    };
    class ResultFunctor {
      public:
        template <class ImageType1, class ImageType2>
          void operator() (ImageType1& out, ImageType2& in) const {
            Operation op = in.value();
            out.value() = op.result();
          }
    };

  public:
    ImageKernel (const Header& header) :
      image (Header::scratch (header).get_image<Operation>()) {
        ThreadedLoop (image).run (InitFunctor(), image);
      }

    void write_back (Image<value_type>& out)
    {
      ThreadedLoop (image).run (ResultFunctor(), out, image);
    }

    void process (Header& header_in)
    {
      auto in = header_in.get_image<value_type>();
      ThreadedLoop (image).run (ProcessFunctor(), image, in);
    }

  protected:
    Image<Operation> image;
};

void run ()
{
  const size_t num_inputs = argument.size() - 2;
  const int op = argument[num_inputs];
  const std::string& output_path = argument.back();

  auto opt = get_options ("axis");
  if (opt.size()) {

    if (num_inputs != 1)
      throw Exception ("Option -axis only applies if a single input image is used");

    const size_t axis = opt[0][0];

    auto image_in = Header::open (argument[0]).get_image<value_type>().with_direct_io (axis);

    if (axis >= image_in.ndim())
      throw Exception ("Cannot perform operation along axis " + str (axis) + "; image only has " + str(image_in.ndim()) + " axes");

    Header header_out (image_in);

    header_out.datatype() = DataType::from_command_line (DataType::Float32);
    header_out.size(axis) = 1;
    squeeze_dim (header_out);

    auto image_out = Header::create (output_path, header_out).get_image<float>();

    auto loop = ThreadedLoop (std::string("computing ") + operations[op] + " along axis " + str(axis) + "...", image_out);

    switch (op) {
      case 0: loop.run  (AxisKernel<Mean>   (axis), image_in, image_out); return;
      case 1: loop.run  (AxisKernel<Median> (axis), image_in, image_out); return;
      case 2: loop.run  (AxisKernel<Sum>    (axis), image_in, image_out); return;
      case 3: loop.run  (AxisKernel<Product>(axis), image_in, image_out); return;
      case 4: loop.run  (AxisKernel<RMS>    (axis), image_in, image_out); return;
      case 5: loop.run  (AxisKernel<NORM2>  (axis), image_in, image_out); return;
      case 6: loop.run  (AxisKernel<Var>    (axis), image_in, image_out); return;
      case 7: loop.run  (AxisKernel<Std>    (axis), image_in, image_out); return;
      case 8: loop.run  (AxisKernel<Min>    (axis), image_in, image_out); return;
      case 9: loop.run  (AxisKernel<Max>    (axis), image_in, image_out); return;
      case 10: loop.run  (AxisKernel<AbsMax> (axis), image_in, image_out); return;
      case 11: loop.run (AxisKernel<MagMax> (axis), image_in, image_out); return;
      default: assert (0);
    }

  } else {

    if (num_inputs < 2)
      throw Exception ("mrmath requires either multiple input images, or the -axis option to be provided");

    // Pre-load all image headers
    std::vector<Header, Eigen::aligned_allocator<Header>> headers_in (num_inputs);

    // Header of first input image is the template to which all other input images are compared
    headers_in[0] = Header::open (argument[0]);
    Header header (headers_in[0]);
    header.datatype() = DataType::from_command_line (DataType::Float32);

    // Wipe any excess unary-dimensional axes
    while (header.size (header.ndim() - 1) == 1)
      header.ndim() = header.ndim() - 1;

    // Verify that dimensions of all input images adequately match
    for (size_t i = 1; i != num_inputs; ++i) {
      const std::string path = argument[i];
      // headers_in.push_back (std::unique_ptr<Header> (new Header (Header::open (path))));
      headers_in[i] = Header::open (path);
      const Header& temp (headers_in[i]);
      if (temp.ndim() < header.ndim())
        throw Exception ("Image " + path + " has fewer axes than first imput image " + header.name());
      for (size_t axis = 0; axis != header.ndim(); ++axis) {
        if (temp.size(axis) != header.size(axis))
          throw Exception ("Dimensions of image " + path + " do not match those of first input image " + header.name());
      }
      for (size_t axis = header.ndim(); axis != temp.ndim(); ++axis) {
        if (temp.size(axis) != 1)
          throw Exception ("Image " + path + " has axis with non-unary dimension beyond first input image " + header.name());
      }
    }

    // Instantiate a kernel depending on the operation requested
    std::unique_ptr<ImageKernelBase> kernel;
    switch (op) {
      case 0:  kernel.reset (new ImageKernel<Mean>    (header)); break;
      case 1:  kernel.reset (new ImageKernel<Median>  (header)); break;
      case 2:  kernel.reset (new ImageKernel<Sum>     (header)); break;
      case 3:  kernel.reset (new ImageKernel<Product> (header)); break;
      case 4:  kernel.reset (new ImageKernel<RMS>     (header)); break;
      case 5:  kernel.reset (new ImageKernel<Var>     (header)); break;
      case 6:  kernel.reset (new ImageKernel<Std>     (header)); break;
      case 7:  kernel.reset (new ImageKernel<Min>     (header)); break;
      case 8:  kernel.reset (new ImageKernel<Max>     (header)); break;
      case 9:  kernel.reset (new ImageKernel<AbsMax>  (header)); break;
      case 10: kernel.reset (new ImageKernel<MagMax>  (header)); break;
      default: assert (0);
    }

    // Feed the input images to the kernel one at a time
    {
      ProgressBar progress (std::string("computing ") + operations[op] + " across "
          + str(headers_in.size()) + " images", num_inputs);
      for (size_t i = 0; i != headers_in.size(); ++i) {
        assert (headers_in[i].valid());
        assert (headers_in[i].is_file_backed());
        kernel->process (headers_in[i]);
        ++progress;
      }
    }

    auto out = Header::create (output_path, header).get_image<value_type>();
    kernel->write_back (out);
  }

}

<commit_msg>mrmath: fix bug in handling of cross-image operations<commit_after>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "command.h"
#include "progressbar.h"
#include "memory.h"
#include "image.h"
#include "algo/threaded_loop.h"
#include "math/math.h"
#include "math/median.h"

#include <limits>
#include <vector>

using namespace MR;
using namespace App;

const char* operations[] = {
  "mean",
  "median",
  "sum",
  "product",
  "rms",
  "norm",
  "var",
  "std",
  "min",
  "max",
  "absmax", // Maximum of absolute values
  "magmax", // Value for which the magnitude is the maximum (i.e. preserves signed-ness)
  NULL
};

void usage ()
{
  AUTHOR = "J-Donald Tournier (jdtournier@gmail.com)";

  DESCRIPTION
    + "compute summary statistic on image intensities either across images, "
    "or along a specified axis for a single image. Supported operations are:"

    + "mean, median, sum, product, rms (root-mean-square value), norm (vector 2-norm), var (unbiased variance), "
    "std (unbiased standard deviation), min, max, absmax (maximum absolute value), "
    "magmax (value with maximum absolute value, preserving its sign)."

    + "See also 'mrcalc' to compute per-voxel operations.";

  ARGUMENTS
  + Argument ("input", "the input image(s).").type_image_in ().allow_multiple()
  + Argument ("operation", "the operation to apply, one of: " + join(operations, ", ") + ".").type_choice (operations)
  + Argument ("output", "the output image.").type_image_out ();

  OPTIONS
  + Option ("axis", "perform operation along a specified axis of a single input image")
    + Argument ("index").type_integer (0)

  + DataType::options();
}

typedef float value_type;

class Mean {
  public:
    Mean () : sum (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += val;
        ++count;
      }
    }
    value_type result () const {
      if (!count)
        return NAN;
      return sum / count;
    }
    double sum;
    size_t count;
};

class Median {
  public:
    Median () { }
    void operator() (value_type val) {
      if (!std::isnan (val))
        values.push_back(val);
    }
    value_type result () {
      return Math::median(values);
    }
    std::vector<value_type> values;
};

class Sum {
  public:
    Sum () : sum (0.0) { }
    void operator() (value_type val) {
      if (std::isfinite (val))
        sum += val;
    }
    value_type result () const {
      return sum;
    }
    double sum;
};

class Product {
  public:
    Product () : product (NAN) { }
    void operator() (value_type val) {
      if (std::isfinite (val))
        product = std::isfinite (product) ? product * val : val;
    }
    value_type result () const {
      return product;
    }
    double product;
};

class RMS {
  public:
    RMS() : sum (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += Math::pow2 (val);
        ++count;
      }
    }
    value_type result() const {
      if (!count)
        return NAN;
      return std::sqrt(sum / count);
    }
    double sum;
    size_t count;
};

class NORM2 {
  public:
    NORM2() : sum (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += Math::pow2 (val);
        ++count;
      }
    }
    value_type result() const {
      if (!count)
        return NAN;
      return std::sqrt(sum);
    }
    double sum;
    size_t count;
};

class Var {
  public:
    Var () : sum (0.0), sum_sqr (0.0), count (0) { }
    void operator() (value_type val) {
      if (std::isfinite (val)) {
        sum += val;
        sum_sqr += Math::pow2 (val);
        ++count;
      }
    }
    value_type result () const {
      if (count < 2)
        return NAN;
      return  (sum_sqr - Math::pow2 (sum) / static_cast<double> (count)) / (static_cast<double> (count) - 1.0);
    }
    double sum, sum_sqr;
    size_t count;
};

class Std : public Var {
  public:
    Std() : Var() { }
    value_type result () const { return std::sqrt (Var::result()); }
};

class Min {
  public:
    Min () : min (std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && val < min)
        min = val;
    }
    value_type result () const { return std::isfinite (min) ? min : NAN; }
    value_type min;
};

class Max {
  public:
    Max () : max (-std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && val > max)
        max = val;
    }
    value_type result () const { return std::isfinite (max) ? max : NAN; }
    value_type max;
};

class AbsMax {
  public:
    AbsMax () : max (-std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && std::abs(val) > max)
        max = std::abs(val);
    }
    value_type result () const { return std::isfinite (max) ? max : NAN; }
    value_type max;
};

class MagMax {
  public:
    MagMax () : max (-std::numeric_limits<value_type>::infinity()) { }
    MagMax (const int i) : max (-std::numeric_limits<value_type>::infinity()) { }
    void operator() (value_type val) {
      if (std::isfinite (val) && (!std::isfinite (max) || std::abs(val) > std::abs (max)))
        max = val;
    }
    value_type result () const { return std::isfinite (max) ? max : NAN; }
    value_type max;
};

template <class Operation>
class AxisKernel {
  public:
    AxisKernel (size_t axis) : axis (axis) { }

    template <class InputImageType, class OutputImageType>
      void operator() (InputImageType& in, OutputImageType& out) {
        Operation op;
        for (auto l = Loop (axis) (in); l; ++l)
          op (in.value());
        out.value() = op.result();
      }
  protected:
    const size_t axis;
};

class ImageKernelBase {
  public:
    virtual void process (Header& image_in) = 0;
    virtual void write_back (Image<value_type>& out) = 0;
};

template <class Operation>
class ImageKernel : public ImageKernelBase {
  protected:
    class InitFunctor {
      public:
        template <class ImageType>
          void operator() (ImageType& out) const { out.value() = Operation(); }
    };
    class ProcessFunctor {
      public:
        template <class ImageType1, class ImageType2>
          void operator() (ImageType1& out, ImageType2& in) const {
            Operation op = out.value();
            op (in.value());
            out.value() = op;
          }
    };
    class ResultFunctor {
      public:
        template <class ImageType1, class ImageType2>
          void operator() (ImageType1& out, ImageType2& in) const {
            Operation op = in.value();
            out.value() = op.result();
          }
    };

  public:
    ImageKernel (const Header& header) :
      image (Header::scratch (header).get_image<Operation>()) {
        ThreadedLoop (image).run (InitFunctor(), image);
      }

    void write_back (Image<value_type>& out)
    {
      ThreadedLoop (image).run (ResultFunctor(), out, image);
    }

    void process (Header& header_in)
    {
      auto in = header_in.get_image<value_type>();
      ThreadedLoop (image).run (ProcessFunctor(), image, in);
    }

  protected:
    Image<Operation> image;
};

void run ()
{
  const size_t num_inputs = argument.size() - 2;
  const int op = argument[num_inputs];
  const std::string& output_path = argument.back();

  auto opt = get_options ("axis");
  if (opt.size()) {

    if (num_inputs != 1)
      throw Exception ("Option -axis only applies if a single input image is used");

    const size_t axis = opt[0][0];

    auto image_in = Header::open (argument[0]).get_image<value_type>().with_direct_io (axis);

    if (axis >= image_in.ndim())
      throw Exception ("Cannot perform operation along axis " + str (axis) + "; image only has " + str(image_in.ndim()) + " axes");

    Header header_out (image_in);

    header_out.datatype() = DataType::from_command_line (DataType::Float32);
    header_out.size(axis) = 1;
    squeeze_dim (header_out);

    auto image_out = Header::create (output_path, header_out).get_image<float>();

    auto loop = ThreadedLoop (std::string("computing ") + operations[op] + " along axis " + str(axis) + "...", image_out);

    switch (op) {
      case 0: loop.run  (AxisKernel<Mean>   (axis), image_in, image_out); return;
      case 1: loop.run  (AxisKernel<Median> (axis), image_in, image_out); return;
      case 2: loop.run  (AxisKernel<Sum>    (axis), image_in, image_out); return;
      case 3: loop.run  (AxisKernel<Product>(axis), image_in, image_out); return;
      case 4: loop.run  (AxisKernel<RMS>    (axis), image_in, image_out); return;
      case 5: loop.run  (AxisKernel<NORM2>  (axis), image_in, image_out); return;
      case 6: loop.run  (AxisKernel<Var>    (axis), image_in, image_out); return;
      case 7: loop.run  (AxisKernel<Std>    (axis), image_in, image_out); return;
      case 8: loop.run  (AxisKernel<Min>    (axis), image_in, image_out); return;
      case 9: loop.run  (AxisKernel<Max>    (axis), image_in, image_out); return;
      case 10: loop.run  (AxisKernel<AbsMax> (axis), image_in, image_out); return;
      case 11: loop.run (AxisKernel<MagMax> (axis), image_in, image_out); return;
      default: assert (0);
    }

  } else {

    if (num_inputs < 2)
      throw Exception ("mrmath requires either multiple input images, or the -axis option to be provided");

    // Pre-load all image headers
    std::vector<Header, Eigen::aligned_allocator<Header>> headers_in (num_inputs);

    // Header of first input image is the template to which all other input images are compared
    headers_in[0] = Header::open (argument[0]);
    Header header (headers_in[0]);
    header.datatype() = DataType::from_command_line (DataType::Float32);

    // Wipe any excess unary-dimensional axes
    while (header.size (header.ndim() - 1) == 1)
      header.ndim() = header.ndim() - 1;

    // Verify that dimensions of all input images adequately match
    for (size_t i = 1; i != num_inputs; ++i) {
      const std::string path = argument[i];
      // headers_in.push_back (std::unique_ptr<Header> (new Header (Header::open (path))));
      headers_in[i] = Header::open (path);
      const Header& temp (headers_in[i]);
      if (temp.ndim() < header.ndim())
        throw Exception ("Image " + path + " has fewer axes than first imput image " + header.name());
      for (size_t axis = 0; axis != header.ndim(); ++axis) {
        if (temp.size(axis) != header.size(axis))
          throw Exception ("Dimensions of image " + path + " do not match those of first input image " + header.name());
      }
      for (size_t axis = header.ndim(); axis != temp.ndim(); ++axis) {
        if (temp.size(axis) != 1)
          throw Exception ("Image " + path + " has axis with non-unary dimension beyond first input image " + header.name());
      }
    }

    // Instantiate a kernel depending on the operation requested
    std::unique_ptr<ImageKernelBase> kernel;
    switch (op) {
      case 0:  kernel.reset (new ImageKernel<Mean>    (header)); break;
      case 1:  kernel.reset (new ImageKernel<Median>  (header)); break;
      case 2:  kernel.reset (new ImageKernel<Sum>     (header)); break;
      case 3:  kernel.reset (new ImageKernel<Product> (header)); break;
      case 4:  kernel.reset (new ImageKernel<RMS>     (header)); break;
      case 5:  kernel.reset (new ImageKernel<NORM2>   (header)); break;
      case 6:  kernel.reset (new ImageKernel<Var>     (header)); break;
      case 7:  kernel.reset (new ImageKernel<Std>     (header)); break;
      case 8:  kernel.reset (new ImageKernel<Min>     (header)); break;
      case 9:  kernel.reset (new ImageKernel<Max>     (header)); break;
      case 10:  kernel.reset (new ImageKernel<AbsMax>  (header)); break;
      case 11: kernel.reset (new ImageKernel<MagMax>  (header)); break;
      default: assert (0);
    }

    // Feed the input images to the kernel one at a time
    {
      ProgressBar progress (std::string("computing ") + operations[op] + " across "
          + str(headers_in.size()) + " images", num_inputs);
      for (size_t i = 0; i != headers_in.size(); ++i) {
        assert (headers_in[i].valid());
        assert (headers_in[i].is_file_backed());
        kernel->process (headers_in[i]);
        ++progress;
      }
    }

    auto out = Header::create (output_path, header).get_image<value_type>();
    kernel->write_back (out);
  }

}

<|endoftext|>


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

#include "shared_realm.hpp"

#include "binding_context.hpp"
#include "impl/external_commit_helper.hpp"
#include "impl/realm_coordinator.hpp"
#include "impl/transact_log_handler.hpp"
#include "object_store.hpp"
#include "schema.hpp"

#include <realm/commit_log.hpp>
#include <realm/group_shared.hpp>

#include <mutex>

using namespace realm;
using namespace realm::_impl;

Realm::Config::Config(const Config& c)
: path(c.path)
, encryption_key(c.encryption_key)
, schema_version(c.schema_version)
, migration_function(c.migration_function)
, read_only(c.read_only)
, in_memory(c.in_memory)
, cache(c.cache)
, disable_format_upgrade(c.disable_format_upgrade)
, automatic_change_notifications(c.automatic_change_notifications)
{
    if (c.schema) {
        schema = std::make_unique<Schema>(*c.schema);
    }
}

Realm::Config::Config() : schema_version(ObjectStore::NotVersioned) { }
Realm::Config::Config(Config&&) = default;
Realm::Config::~Config() = default;

Realm::Config& Realm::Config::operator=(realm::Realm::Config const& c)
{
    if (&c != this) {
        *this = Config(c);
    }
    return *this;
}

Realm::Realm(Config config, bool auto_refresh)
: m_config(std::move(config))
, m_auto_refresh(auto_refresh)
{
    open_with_config(m_config, m_history, m_shared_group, m_read_only_group);

    if (m_read_only_group) {
        m_group = m_read_only_group.get();
    }
}

void Realm::open_with_config(const Config& config,
                             std::unique_ptr<Replication>& history,
                             std::unique_ptr<SharedGroup>& shared_group,
                             std::unique_ptr<Group>& read_only_group)
{
    try {
        if (config.read_only) {
            read_only_group = std::make_unique<Group>(config.path, config.encryption_key.data(), Group::mode_ReadOnly);
        }
        else {
            if (config.encryption_key.data() && config.encryption_key.size() != 64) {
                throw InvalidEncryptionKeyException();
            }
            history = realm::make_client_history(config.path, config.encryption_key.data());
            SharedGroup::DurabilityLevel durability = config.in_memory ? SharedGroup::durability_MemOnly :
                                                                           SharedGroup::durability_Full;
            shared_group = std::make_unique<SharedGroup>(*history, durability, config.encryption_key.data(), !config.disable_format_upgrade);
        }
    }
    catch (util::File::PermissionDenied const& ex) {
        throw RealmFileException(RealmFileException::Kind::PermissionDenied, ex.get_path(),
                                 "Unable to open a realm at path '" + ex.get_path() +
                                 "'. Please use a path where your app has " + (config.read_only ? "read" : "read-write") + " permissions.");
    }
    catch (util::File::Exists const& ex) {
        throw RealmFileException(RealmFileException::Kind::Exists, ex.get_path(),
                                 "File at path '" + ex.get_path() + "' already exists.");
    }
    catch (util::File::NotFound const& ex) {
        throw RealmFileException(RealmFileException::Kind::NotFound, ex.get_path(),
                                 "File at path '" + ex.get_path() + "' does not exist.");
    }
    catch (util::File::AccessError const& ex) {
        throw RealmFileException(RealmFileException::Kind::AccessError, ex.get_path(),
                                 "Unable to open a realm at path '" + ex.get_path() + "'");
    }
    catch (IncompatibleLockFile const& ex) {
        throw RealmFileException(RealmFileException::Kind::IncompatibleLockFile, config.path,
                                 "Realm file is currently open in another process "
                                 "which cannot share access with this process. All processes sharing a single file must be the same architecture.");
    }
    catch (FileFormatUpgradeRequired const& ex) {
        throw RealmFileException(RealmFileException::Kind::FormatUpgradeRequired, config.path,
                                 "The Realm file format must be allowed to be upgraded "
                                 "in order to proceed.");
    }
}

void Realm::init(std::shared_ptr<RealmCoordinator> coordinator)
{
    m_coordinator = std::move(coordinator);

    // if there is an existing realm at the current path steal its schema/column mapping
    if (auto existing = m_coordinator->get_schema()) {
        m_config.schema = std::make_unique<Schema>(*existing);
        return;
    }

    try {
        // otherwise get the schema from the group
        auto target_schema = std::move(m_config.schema);
        auto target_schema_version = m_config.schema_version;
        m_config.schema_version = ObjectStore::get_schema_version(read_group());
        m_config.schema = std::make_unique<Schema>(ObjectStore::schema_from_group(read_group()));

        // if a target schema is supplied, verify that it matches or migrate to
        // it, as neeeded
        if (target_schema) {
            if (m_config.read_only) {
                if (m_config.schema_version == ObjectStore::NotVersioned) {
                    throw UnitializedRealmException("Can't open an un-initialized Realm without a Schema");
                }
                target_schema->validate();
                ObjectStore::verify_schema(*m_config.schema, *target_schema, true);
                m_config.schema = std::move(target_schema);
            }
            else {
                update_schema(std::move(target_schema), target_schema_version);
            }

            if (!m_config.read_only) {
                // End the read transaction created to validation/update the
                // schema to avoid pinning the version even if the user never
                // actually reads data
                invalidate();
            }
        }
    }
    catch (...) {
        // Trying to unregister from the coordinator before we finish
        // construction will result in a deadlock
        m_coordinator = nullptr;
        throw;
    }
}

Realm::~Realm()
{
    if (m_coordinator) {
        m_coordinator->unregister_realm(this);
    }
}

Group *Realm::read_group()
{
    if (!m_group) {
        m_group = &const_cast<Group&>(m_shared_group->begin_read());
    }
    return m_group;
}

SharedRealm Realm::get_shared_realm(Config config)
{
    auto coordinator = RealmCoordinator::get_coordinator(config.path);
    return coordinator->get_realm(std::move(config));
}

void Realm::update_schema(std::unique_ptr<Schema> schema, uint64_t version)
{
    schema->validate();

    auto needs_update = [&] {
        // If the schema version matches, just verify that the schema itself also matches
        bool needs_write = !m_config.read_only && (m_config.schema_version != version || ObjectStore::needs_update(*m_config.schema, *schema));
        if (needs_write) {
            return true;
        }

        ObjectStore::verify_schema(*m_config.schema, *schema, m_config.read_only);
        m_config.schema = std::move(schema);
        m_config.schema_version = version;
        m_coordinator->update_schema(*m_config.schema);
        return false;
    };

    if (!needs_update()) {
        return;
    }

    read_group();
    transaction::begin(*m_shared_group, m_binding_context.get(),
                       /* error on schema changes */ false);

    struct WriteTransactionGuard {
        Realm& realm;
        ~WriteTransactionGuard() {
            if (realm.is_in_transaction()) {
                realm.cancel_transaction();
            }
        }
    } write_transaction_guard{*this};

    // Recheck the schema version after beginning the write transaction
    // If it changed then someone else initialized the schema and we need to
    // recheck everything
    auto current_schema_version = ObjectStore::get_schema_version(read_group());
    if (current_schema_version != m_config.schema_version) {
        m_config.schema_version = current_schema_version;
        *m_config.schema = ObjectStore::schema_from_group(read_group());

        if (!needs_update()) {
            cancel_transaction();
            return;
        }
    }

    Config old_config(m_config);
    auto migration_function = [&](Group*,  Schema&) {
        SharedRealm old_realm(new Realm(old_config));
        // Need to open in read-write mode so that it uses a SharedGroup, but
        // users shouldn't actually be able to write via the old realm
        old_realm->m_config.read_only = true;

        if (m_config.migration_function) {
            m_config.migration_function(old_realm, shared_from_this());
        }
    };

    try {
        m_config.schema = std::move(schema);
        m_config.schema_version = version;

        ObjectStore::update_realm_with_schema(read_group(), *old_config.schema,
                                              version, *m_config.schema,
                                              migration_function);
        commit_transaction();
    }
    catch (...) {
        m_config.schema = std::move(old_config.schema);
        m_config.schema_version = old_config.schema_version;
        throw;
    }

    m_coordinator->update_schema(*m_config.schema);
}

static void check_read_write(Realm *realm)
{
    if (realm->config().read_only) {
        throw InvalidTransactionException("Can't perform transactions on read-only Realms.");
    }
}

void Realm::verify_thread() const
{
    if (m_thread_id != std::this_thread::get_id()) {
        throw IncorrectThreadException();
    }
}

void Realm::verify_in_write() const
{
    if (!is_in_transaction()) {
        throw InvalidTransactionException("Cannot modify persisted objects outside of a write transaction.");
    }
}

bool Realm::is_in_transaction() const noexcept
{
    if (!m_shared_group) {
        return false;
    }
    return m_shared_group->get_transact_stage() == SharedGroup::transact_Writing;
}

void Realm::begin_transaction()
{
    check_read_write(this);
    verify_thread();

    if (is_in_transaction()) {
        throw InvalidTransactionException("The Realm is already in a write transaction");
    }

    // make sure we have a read transaction
    read_group();

    transaction::begin(*m_shared_group, m_binding_context.get());
}

void Realm::commit_transaction()
{
    check_read_write(this);
    verify_thread();

    if (!is_in_transaction()) {
        throw InvalidTransactionException("Can't commit a non-existing write transaction");
    }

    transaction::commit(*m_shared_group, m_binding_context.get());
    m_coordinator->send_commit_notifications();
}

void Realm::cancel_transaction()
{
    check_read_write(this);
    verify_thread();

    if (!is_in_transaction()) {
        throw InvalidTransactionException("Can't cancel a non-existing write transaction");
    }

    transaction::cancel(*m_shared_group, m_binding_context.get());
}

void Realm::invalidate()
{
    verify_thread();
    check_read_write(this);

    if (is_in_transaction()) {
        cancel_transaction();
    }
    if (!m_group) {
        return;
    }

    m_shared_group->end_read();
    m_group = nullptr;
}

bool Realm::compact()
{
    verify_thread();

    if (m_config.read_only) {
        throw InvalidTransactionException("Can't compact a read-only Realm");
    }
    if (is_in_transaction()) {
        throw InvalidTransactionException("Can't compact a Realm within a write transaction");
    }

    Group* group = read_group();
    for (auto &object_schema : *m_config.schema) {
        ObjectStore::table_for_object_type(group, object_schema.name)->optimize();
    }
    m_shared_group->end_read();
    m_group = nullptr;

    return m_shared_group->compact();
}

void Realm::notify()
{
    verify_thread();

    if (m_shared_group->has_changed()) { // Throws
        if (m_binding_context) {
            m_binding_context->changes_available();
        }
        if (m_auto_refresh) {
            if (m_group) {
                m_coordinator->advance_to_ready(*this);
            }
            else if (m_binding_context) {
                m_binding_context->did_change({}, {});
            }
        }
    }
    else {
        m_coordinator->process_available_async(*this);
    }
}

bool Realm::refresh()
{
    verify_thread();
    check_read_write(this);

    // can't be any new changes if we're in a write transaction
    if (is_in_transaction()) {
        return false;
    }

    // advance transaction if database has changed
    if (!m_shared_group->has_changed()) { // Throws
        return false;
    }

    if (m_group) {
        transaction::advance(*m_shared_group, m_binding_context.get());
        m_coordinator->process_available_async(*this);
    }
    else {
        // Create the read transaction
        read_group();
    }

    return true;
}

void Realm::set_auto_refresh(bool auto_refresh)
{
    m_auto_refresh = auto_refresh;
    m_coordinator->set_auto_refresh_for(this, auto_refresh);
}

bool Realm::can_deliver_notifications() const noexcept
{
    if (m_config.read_only) {
        return false;
    }

    if (m_binding_context && !m_binding_context->can_deliver_notifications()) {
        return false;
    }

    return true;
}

uint64_t Realm::get_schema_version(const realm::Realm::Config &config)
{
    auto coordinator = RealmCoordinator::get_existing_coordinator(config.path);
    if (coordinator) {
        return coordinator->get_schema_version();
    }

    return ObjectStore::get_schema_version(Realm(config).read_group());
}

void Realm::close()
{
    verify_thread();

    if (m_coordinator) {
        m_coordinator->unregister_realm(this);
    }

    m_group = nullptr;
    m_shared_group = nullptr;
    m_history = nullptr;
    m_read_only_group = nullptr;
    m_binding_context = nullptr;
    m_coordinator = nullptr;
}
<commit_msg>Change the order of destruction of realm_coordinator and shared_group<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#include "shared_realm.hpp"

#include "binding_context.hpp"
#include "impl/external_commit_helper.hpp"
#include "impl/realm_coordinator.hpp"
#include "impl/transact_log_handler.hpp"
#include "object_store.hpp"
#include "schema.hpp"

#include <realm/commit_log.hpp>
#include <realm/group_shared.hpp>

#include <mutex>

using namespace realm;
using namespace realm::_impl;

Realm::Config::Config(const Config& c)
: path(c.path)
, encryption_key(c.encryption_key)
, schema_version(c.schema_version)
, migration_function(c.migration_function)
, read_only(c.read_only)
, in_memory(c.in_memory)
, cache(c.cache)
, disable_format_upgrade(c.disable_format_upgrade)
, automatic_change_notifications(c.automatic_change_notifications)
{
    if (c.schema) {
        schema = std::make_unique<Schema>(*c.schema);
    }
}

Realm::Config::Config() : schema_version(ObjectStore::NotVersioned) { }
Realm::Config::Config(Config&&) = default;
Realm::Config::~Config() = default;

Realm::Config& Realm::Config::operator=(realm::Realm::Config const& c)
{
    if (&c != this) {
        *this = Config(c);
    }
    return *this;
}

Realm::Realm(Config config, bool auto_refresh)
: m_config(std::move(config))
, m_auto_refresh(auto_refresh)
{
    open_with_config(m_config, m_history, m_shared_group, m_read_only_group);

    if (m_read_only_group) {
        m_group = m_read_only_group.get();
    }
}

void Realm::open_with_config(const Config& config,
                             std::unique_ptr<Replication>& history,
                             std::unique_ptr<SharedGroup>& shared_group,
                             std::unique_ptr<Group>& read_only_group)
{
    try {
        if (config.read_only) {
            read_only_group = std::make_unique<Group>(config.path, config.encryption_key.data(), Group::mode_ReadOnly);
        }
        else {
            if (config.encryption_key.data() && config.encryption_key.size() != 64) {
                throw InvalidEncryptionKeyException();
            }
            history = realm::make_client_history(config.path, config.encryption_key.data());
            SharedGroup::DurabilityLevel durability = config.in_memory ? SharedGroup::durability_MemOnly :
                                                                           SharedGroup::durability_Full;
            shared_group = std::make_unique<SharedGroup>(*history, durability, config.encryption_key.data(), !config.disable_format_upgrade);
        }
    }
    catch (util::File::PermissionDenied const& ex) {
        throw RealmFileException(RealmFileException::Kind::PermissionDenied, ex.get_path(),
                                 "Unable to open a realm at path '" + ex.get_path() +
                                 "'. Please use a path where your app has " + (config.read_only ? "read" : "read-write") + " permissions.");
    }
    catch (util::File::Exists const& ex) {
        throw RealmFileException(RealmFileException::Kind::Exists, ex.get_path(),
                                 "File at path '" + ex.get_path() + "' already exists.");
    }
    catch (util::File::NotFound const& ex) {
        throw RealmFileException(RealmFileException::Kind::NotFound, ex.get_path(),
                                 "File at path '" + ex.get_path() + "' does not exist.");
    }
    catch (util::File::AccessError const& ex) {
        throw RealmFileException(RealmFileException::Kind::AccessError, ex.get_path(),
                                 "Unable to open a realm at path '" + ex.get_path() + "'");
    }
    catch (IncompatibleLockFile const& ex) {
        throw RealmFileException(RealmFileException::Kind::IncompatibleLockFile, config.path,
                                 "Realm file is currently open in another process "
                                 "which cannot share access with this process. All processes sharing a single file must be the same architecture.");
    }
    catch (FileFormatUpgradeRequired const& ex) {
        throw RealmFileException(RealmFileException::Kind::FormatUpgradeRequired, config.path,
                                 "The Realm file format must be allowed to be upgraded "
                                 "in order to proceed.");
    }
}

void Realm::init(std::shared_ptr<RealmCoordinator> coordinator)
{
    m_coordinator = std::move(coordinator);

    // if there is an existing realm at the current path steal its schema/column mapping
    if (auto existing = m_coordinator->get_schema()) {
        m_config.schema = std::make_unique<Schema>(*existing);
        return;
    }

    try {
        // otherwise get the schema from the group
        auto target_schema = std::move(m_config.schema);
        auto target_schema_version = m_config.schema_version;
        m_config.schema_version = ObjectStore::get_schema_version(read_group());
        m_config.schema = std::make_unique<Schema>(ObjectStore::schema_from_group(read_group()));

        // if a target schema is supplied, verify that it matches or migrate to
        // it, as neeeded
        if (target_schema) {
            if (m_config.read_only) {
                if (m_config.schema_version == ObjectStore::NotVersioned) {
                    throw UnitializedRealmException("Can't open an un-initialized Realm without a Schema");
                }
                target_schema->validate();
                ObjectStore::verify_schema(*m_config.schema, *target_schema, true);
                m_config.schema = std::move(target_schema);
            }
            else {
                update_schema(std::move(target_schema), target_schema_version);
            }

            if (!m_config.read_only) {
                // End the read transaction created to validation/update the
                // schema to avoid pinning the version even if the user never
                // actually reads data
                invalidate();
            }
        }
    }
    catch (...) {
        // Trying to unregister from the coordinator before we finish
        // construction will result in a deadlock
        m_coordinator = nullptr;
        throw;
    }
}

Realm::~Realm()
{
    if (m_coordinator) {
        m_coordinator->unregister_realm(this);
    }
}

Group *Realm::read_group()
{
    if (!m_group) {
        m_group = &const_cast<Group&>(m_shared_group->begin_read());
    }
    return m_group;
}

SharedRealm Realm::get_shared_realm(Config config)
{
    auto coordinator = RealmCoordinator::get_coordinator(config.path);
    return coordinator->get_realm(std::move(config));
}

void Realm::update_schema(std::unique_ptr<Schema> schema, uint64_t version)
{
    schema->validate();

    auto needs_update = [&] {
        // If the schema version matches, just verify that the schema itself also matches
        bool needs_write = !m_config.read_only && (m_config.schema_version != version || ObjectStore::needs_update(*m_config.schema, *schema));
        if (needs_write) {
            return true;
        }

        ObjectStore::verify_schema(*m_config.schema, *schema, m_config.read_only);
        m_config.schema = std::move(schema);
        m_config.schema_version = version;
        m_coordinator->update_schema(*m_config.schema);
        return false;
    };

    if (!needs_update()) {
        return;
    }

    read_group();
    transaction::begin(*m_shared_group, m_binding_context.get(),
                       /* error on schema changes */ false);

    struct WriteTransactionGuard {
        Realm& realm;
        ~WriteTransactionGuard() {
            if (realm.is_in_transaction()) {
                realm.cancel_transaction();
            }
        }
    } write_transaction_guard{*this};

    // Recheck the schema version after beginning the write transaction
    // If it changed then someone else initialized the schema and we need to
    // recheck everything
    auto current_schema_version = ObjectStore::get_schema_version(read_group());
    if (current_schema_version != m_config.schema_version) {
        m_config.schema_version = current_schema_version;
        *m_config.schema = ObjectStore::schema_from_group(read_group());

        if (!needs_update()) {
            cancel_transaction();
            return;
        }
    }

    Config old_config(m_config);
    auto migration_function = [&](Group*,  Schema&) {
        SharedRealm old_realm(new Realm(old_config));
        // Need to open in read-write mode so that it uses a SharedGroup, but
        // users shouldn't actually be able to write via the old realm
        old_realm->m_config.read_only = true;

        if (m_config.migration_function) {
            m_config.migration_function(old_realm, shared_from_this());
        }
    };

    try {
        m_config.schema = std::move(schema);
        m_config.schema_version = version;

        ObjectStore::update_realm_with_schema(read_group(), *old_config.schema,
                                              version, *m_config.schema,
                                              migration_function);
        commit_transaction();
    }
    catch (...) {
        m_config.schema = std::move(old_config.schema);
        m_config.schema_version = old_config.schema_version;
        throw;
    }

    m_coordinator->update_schema(*m_config.schema);
}

static void check_read_write(Realm *realm)
{
    if (realm->config().read_only) {
        throw InvalidTransactionException("Can't perform transactions on read-only Realms.");
    }
}

void Realm::verify_thread() const
{
    if (m_thread_id != std::this_thread::get_id()) {
        throw IncorrectThreadException();
    }
}

void Realm::verify_in_write() const
{
    if (!is_in_transaction()) {
        throw InvalidTransactionException("Cannot modify persisted objects outside of a write transaction.");
    }
}

bool Realm::is_in_transaction() const noexcept
{
    if (!m_shared_group) {
        return false;
    }
    return m_shared_group->get_transact_stage() == SharedGroup::transact_Writing;
}

void Realm::begin_transaction()
{
    check_read_write(this);
    verify_thread();

    if (is_in_transaction()) {
        throw InvalidTransactionException("The Realm is already in a write transaction");
    }

    // make sure we have a read transaction
    read_group();

    transaction::begin(*m_shared_group, m_binding_context.get());
}

void Realm::commit_transaction()
{
    check_read_write(this);
    verify_thread();

    if (!is_in_transaction()) {
        throw InvalidTransactionException("Can't commit a non-existing write transaction");
    }

    transaction::commit(*m_shared_group, m_binding_context.get());
    m_coordinator->send_commit_notifications();
}

void Realm::cancel_transaction()
{
    check_read_write(this);
    verify_thread();

    if (!is_in_transaction()) {
        throw InvalidTransactionException("Can't cancel a non-existing write transaction");
    }

    transaction::cancel(*m_shared_group, m_binding_context.get());
}

void Realm::invalidate()
{
    verify_thread();
    check_read_write(this);

    if (is_in_transaction()) {
        cancel_transaction();
    }
    if (!m_group) {
        return;
    }

    m_shared_group->end_read();
    m_group = nullptr;
}

bool Realm::compact()
{
    verify_thread();

    if (m_config.read_only) {
        throw InvalidTransactionException("Can't compact a read-only Realm");
    }
    if (is_in_transaction()) {
        throw InvalidTransactionException("Can't compact a Realm within a write transaction");
    }

    Group* group = read_group();
    for (auto &object_schema : *m_config.schema) {
        ObjectStore::table_for_object_type(group, object_schema.name)->optimize();
    }
    m_shared_group->end_read();
    m_group = nullptr;

    return m_shared_group->compact();
}

void Realm::notify()
{
    verify_thread();

    if (m_shared_group->has_changed()) { // Throws
        if (m_binding_context) {
            m_binding_context->changes_available();
        }
        if (m_auto_refresh) {
            if (m_group) {
                m_coordinator->advance_to_ready(*this);
            }
            else if (m_binding_context) {
                m_binding_context->did_change({}, {});
            }
        }
    }
    else {
        m_coordinator->process_available_async(*this);
    }
}

bool Realm::refresh()
{
    verify_thread();
    check_read_write(this);

    // can't be any new changes if we're in a write transaction
    if (is_in_transaction()) {
        return false;
    }

    // advance transaction if database has changed
    if (!m_shared_group->has_changed()) { // Throws
        return false;
    }

    if (m_group) {
        transaction::advance(*m_shared_group, m_binding_context.get());
        m_coordinator->process_available_async(*this);
    }
    else {
        // Create the read transaction
        read_group();
    }

    return true;
}

void Realm::set_auto_refresh(bool auto_refresh)
{
    m_auto_refresh = auto_refresh;
    m_coordinator->set_auto_refresh_for(this, auto_refresh);
}

bool Realm::can_deliver_notifications() const noexcept
{
    if (m_config.read_only) {
        return false;
    }

    if (m_binding_context && !m_binding_context->can_deliver_notifications()) {
        return false;
    }

    return true;
}

uint64_t Realm::get_schema_version(const realm::Realm::Config &config)
{
    auto coordinator = RealmCoordinator::get_existing_coordinator(config.path);
    if (coordinator) {
        return coordinator->get_schema_version();
    }

    return ObjectStore::get_schema_version(Realm(config).read_group());
}

void Realm::close()
{
    verify_thread();

    if (m_coordinator) {
        m_coordinator->unregister_realm(this);
    }

    m_coordinator = nullptr;
    m_group = nullptr;
    m_shared_group = nullptr;
    m_history = nullptr;
    m_read_only_group = nullptr;
    m_binding_context = nullptr;
}
<|endoftext|>


<commit_before>/*********************************************************************************
* Copyright (c) 2013 David D. Marshall <ddmarsha@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    David D. Marshall - initial code and implementation
********************************************************************************/

#ifndef eli_geom_surface_piecewise_body_of_revolution_creator_hpp
#define eli_geom_surface_piecewise_body_of_revolution_creator_hpp

#include <list>
#include <iterator>

#include "eli/code_eli.hpp"

#include "eli/util/tolerance.hpp"

#include "eli/geom/curve/piecewise.hpp"
#include "eli/geom/curve/piecewise_creator.hpp"

#include "eli/geom/surface/piecewise.hpp"
#include "eli/geom/surface/bezier.hpp"

namespace eli
{
  namespace geom
  {
    namespace surface
    {
      template<typename data__, unsigned short dim__, typename tol__>
      bool create_body_of_revolution(piecewise<bezier, data__, dim__, tol__> &ps,
                                     const eli::geom::curve::piecewise<eli::geom::curve::bezier, data__, dim__, tol__> &pc,
                                     int axis, bool outward_normal, bool match_uparm = false)
      {
        typedef piecewise<bezier, data__, dim__, tol__> piecewise_surface_type;
        typedef eli::geom::curve::piecewise<eli::geom::curve::bezier, data__, dim__, tol__> piecewise_curve_type;
        typedef eli::geom::curve::piecewise_circle_creator<data__, dim__, tol__> circle_creator_type;
        typedef typename piecewise_curve_type::curve_type curve_type;
        typedef typename piecewise_surface_type::surface_type surface_type;
        typedef typename curve_type::point_type point_type;
        typedef typename curve_type::data_type data_type;
        typedef typename curve_type::index_type index_type;

        curve_type c, arc;
        surface_type s[4];
        piecewise_curve_type pc_circle;
        point_type origin, normal, start;
        data_type du, dv;
        index_type i, j, pp, qq, nu=pc.number_segments(), nv=4, udeg, vdeg;

        // resize the surface
        if ( match_uparm )
        {
          vector<data_type> umap, du;
          pc.get_pmap( umap );

          for ( i = 0; i < nu; i++ )
          {
            du.push_back( umap[ i + 1 ] - umap[ i ] );
          }

          ps.init_uv( du.begin(), du.end(), nv, 1, umap[0] );
        }
        else
        {
          ps.init_uv(nu, nv);
        }

        // set the axis of rotation
        switch(axis)
        {
          case(0):
          {
            normal << 1, 0, 0;
            break;
          }
          case(1):
          {
            normal << 0, 1, 0;
            break;
          }
          case(2):
          {
            normal << 0, 0, 1;
            break;
          }
          default:
          {
            assert(false);
            return false;
          }
        }
        if (outward_normal)
        {
          normal*=-1;
        }

        // cycle through each curve segment
        circle_creator_type circle_creator;
        for (pp=0; pp<nu; ++pp)
        {
          // resize the surface patch
          vdeg=3;
          pc.get(c, du, pp);
          udeg = c.degree();

          s[0].resize(udeg, vdeg);
          s[1].resize(udeg, vdeg);
          s[2].resize(udeg, vdeg);
          s[3].resize(udeg, vdeg);

          // cycle through each control point in current curve and create patch control points
          for (i=0; i<=udeg; ++i)
          {
            // set up the vectors for this circle
            start=c.get_control_point(i);
            origin=normal.dot(start)*normal;

            // get the circle
            circle_creator.set(start, origin, normal);
            if (!circle_creator.create(pc_circle))
            {
              assert(false);
              return false;
            }

            // for each segment of circle set the control points
            for (qq=0; qq<4; ++qq)
            {
              pc_circle.get(arc, dv, qq);
              for (j=0; j<4; ++j)
              {
                s[qq].set_control_point(arc.get_control_point(j), i, j);
              }
            }
          }

          // set the surface patches
          for (qq=0; qq<4; ++qq)
          {
            ps.set(s[qq], pp, qq);
          }
        }

        return true;
      }
    }
  }
}
#endif
<commit_msg>Add missing std:: required by some pedantic compilers.<commit_after>/*********************************************************************************
* Copyright (c) 2013 David D. Marshall <ddmarsha@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    David D. Marshall - initial code and implementation
********************************************************************************/

#ifndef eli_geom_surface_piecewise_body_of_revolution_creator_hpp
#define eli_geom_surface_piecewise_body_of_revolution_creator_hpp

#include <list>
#include <iterator>

#include "eli/code_eli.hpp"

#include "eli/util/tolerance.hpp"

#include "eli/geom/curve/piecewise.hpp"
#include "eli/geom/curve/piecewise_creator.hpp"

#include "eli/geom/surface/piecewise.hpp"
#include "eli/geom/surface/bezier.hpp"

namespace eli
{
  namespace geom
  {
    namespace surface
    {
      template<typename data__, unsigned short dim__, typename tol__>
      bool create_body_of_revolution(piecewise<bezier, data__, dim__, tol__> &ps,
                                     const eli::geom::curve::piecewise<eli::geom::curve::bezier, data__, dim__, tol__> &pc,
                                     int axis, bool outward_normal, bool match_uparm = false)
      {
        typedef piecewise<bezier, data__, dim__, tol__> piecewise_surface_type;
        typedef eli::geom::curve::piecewise<eli::geom::curve::bezier, data__, dim__, tol__> piecewise_curve_type;
        typedef eli::geom::curve::piecewise_circle_creator<data__, dim__, tol__> circle_creator_type;
        typedef typename piecewise_curve_type::curve_type curve_type;
        typedef typename piecewise_surface_type::surface_type surface_type;
        typedef typename curve_type::point_type point_type;
        typedef typename curve_type::data_type data_type;
        typedef typename curve_type::index_type index_type;

        curve_type c, arc;
        surface_type s[4];
        piecewise_curve_type pc_circle;
        point_type origin, normal, start;
        data_type du, dv;
        index_type i, j, pp, qq, nu=pc.number_segments(), nv=4, udeg, vdeg;

        // resize the surface
        if ( match_uparm )
        {
          std::vector<data_type> umap, du;
          pc.get_pmap( umap );

          for ( i = 0; i < nu; i++ )
          {
            du.push_back( umap[ i + 1 ] - umap[ i ] );
          }

          ps.init_uv( du.begin(), du.end(), nv, 1, umap[0] );
        }
        else
        {
          ps.init_uv(nu, nv);
        }

        // set the axis of rotation
        switch(axis)
        {
          case(0):
          {
            normal << 1, 0, 0;
            break;
          }
          case(1):
          {
            normal << 0, 1, 0;
            break;
          }
          case(2):
          {
            normal << 0, 0, 1;
            break;
          }
          default:
          {
            assert(false);
            return false;
          }
        }
        if (outward_normal)
        {
          normal*=-1;
        }

        // cycle through each curve segment
        circle_creator_type circle_creator;
        for (pp=0; pp<nu; ++pp)
        {
          // resize the surface patch
          vdeg=3;
          pc.get(c, du, pp);
          udeg = c.degree();

          s[0].resize(udeg, vdeg);
          s[1].resize(udeg, vdeg);
          s[2].resize(udeg, vdeg);
          s[3].resize(udeg, vdeg);

          // cycle through each control point in current curve and create patch control points
          for (i=0; i<=udeg; ++i)
          {
            // set up the vectors for this circle
            start=c.get_control_point(i);
            origin=normal.dot(start)*normal;

            // get the circle
            circle_creator.set(start, origin, normal);
            if (!circle_creator.create(pc_circle))
            {
              assert(false);
              return false;
            }

            // for each segment of circle set the control points
            for (qq=0; qq<4; ++qq)
            {
              pc_circle.get(arc, dv, qq);
              for (j=0; j<4; ++j)
              {
                s[qq].set_control_point(arc.get_control_point(j), i, j);
              }
            }
          }

          // set the surface patches
          for (qq=0; qq<4; ++qq)
          {
            ps.set(s[qq], pp, qq);
          }
        }

        return true;
      }
    }
  }
}
#endif
<|endoftext|>


<commit_before>#include "cnn/devices.h"

#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>

#include "cnn/cuda.h"
#include "cnn/cnn.h"

using namespace std;

namespace cnn {

Device::~Device() {}

DeviceMemCheckpoint Device::mark(ComputationGraph *cg) {
  cg->incremental_forward(); // needed so that we actually allocate the needed memory
                             // for all existing nodes.
  DeviceMemCheckpoint cp;
  for(size_t i = 0; i < 3; ++i)
    cp.used[i] = pools[i]->used;
  return cp;
}

void Device::revert(DeviceMemCheckpoint cp) {
  for(size_t i = 0; i < 3; ++i) {
    assert(cp.used[i] <= pools[i]->used);
    pools[i]->used = cp.used[i];
  }
}

void Device::allocate_tensor(DeviceMempool mp, Tensor & tens) {
  assert(mp != DeviceMempool::NONE);
  assert(pools[(int)mp] != nullptr);
  tens.v = (float*)pools[(int)mp]->allocate(tens.d.size());
  tens.mem_pool = mp;
}

#if HAVE_CUDA
Device_GPU::Device_GPU(int my_id, int mb, int device_id) :
    Device(my_id, DeviceType::GPU, &gpu_mem), cuda_device_id(device_id), gpu_mem(device_id) {
  CUDA_CHECK(cudaSetDevice(device_id));
  CUBLAS_CHECK(cublasCreate(&cublas_handle));
  CUBLAS_CHECK(cublasSetPointerMode(cublas_handle, CUBLAS_POINTER_MODE_DEVICE));
  kSCALAR_MINUSONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ZERO = (float*)gpu_mem.malloc(sizeof(float));
  float minusone = -1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_MINUSONE, &minusone, sizeof(float), cudaMemcpyHostToDevice));
  float one = 1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ONE, &one, sizeof(float), cudaMemcpyHostToDevice));
  float zero = 0;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ZERO, &zero, sizeof(float), cudaMemcpyHostToDevice));

  // Initialize the Eigen device
  estream = new Eigen::CudaStreamDevice(device_id);
  edevice = new Eigen::GpuDevice(estream);

  // this is the big memory allocation. Do it in stages to make sure things are aligned.
  size_t byte_count = (size_t)((mb << 10)/3) << 10;
  for(size_t i = 0; i < 3; ++i)
    pools[i] = new AlignedMemoryPool(byte_count, mem);
}

Device_GPU::~Device_GPU() {}
#endif

// TODO we should be able to configure this carefully with a configuration
// script
// CPU -- 0 params
//     -- 50mb fxs
//     -- 50mb dEdfx
Device_CPU::Device_CPU(int my_id, int mb, bool shared) :
    Device(my_id, DeviceType::CPU, &cpu_mem), shmem(mem) {
  if (shared) shmem = new SharedAllocator();
  kSCALAR_MINUSONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_MINUSONE = -1;
  kSCALAR_ONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ONE = 1;
  kSCALAR_ZERO = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ZERO = 0;

  // Initialize the Eigen device
  edevice = new Eigen::DefaultDevice;

  // this is the big memory allocation. Do it in stages to make sure things are aligned.
  size_t byte_count = (size_t)((mb << 10)/3) << 10;
  for(size_t i = 0; i < 3; ++i)
    pools[i] = new AlignedMemoryPool(byte_count, mem);
}

Device_CPU::~Device_CPU() {}

} // namespace cnn
<commit_msg>Fixed bug forgetting to multiply by float size<commit_after>#include "cnn/devices.h"

#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>

#include "cnn/cuda.h"
#include "cnn/cnn.h"

using namespace std;

namespace cnn {

Device::~Device() {}

DeviceMemCheckpoint Device::mark(ComputationGraph *cg) {
  cg->incremental_forward(); // needed so that we actually allocate the needed memory
                             // for all existing nodes.
  DeviceMemCheckpoint cp;
  for(size_t i = 0; i < 3; ++i)
    cp.used[i] = pools[i]->used;
  return cp;
}

void Device::revert(DeviceMemCheckpoint cp) {
  for(size_t i = 0; i < 3; ++i) {
    assert(cp.used[i] <= pools[i]->used);
    pools[i]->used = cp.used[i];
  }
}

void Device::allocate_tensor(DeviceMempool mp, Tensor & tens) {
  assert(mp != DeviceMempool::NONE);
  assert(pools[(int)mp] != nullptr);
  tens.v = (float*)pools[(int)mp]->allocate(tens.d.size() * sizeof(float));
  tens.mem_pool = mp;
}

#if HAVE_CUDA
Device_GPU::Device_GPU(int my_id, int mb, int device_id) :
    Device(my_id, DeviceType::GPU, &gpu_mem), cuda_device_id(device_id), gpu_mem(device_id) {
  CUDA_CHECK(cudaSetDevice(device_id));
  CUBLAS_CHECK(cublasCreate(&cublas_handle));
  CUBLAS_CHECK(cublasSetPointerMode(cublas_handle, CUBLAS_POINTER_MODE_DEVICE));
  kSCALAR_MINUSONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ZERO = (float*)gpu_mem.malloc(sizeof(float));
  float minusone = -1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_MINUSONE, &minusone, sizeof(float), cudaMemcpyHostToDevice));
  float one = 1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ONE, &one, sizeof(float), cudaMemcpyHostToDevice));
  float zero = 0;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ZERO, &zero, sizeof(float), cudaMemcpyHostToDevice));

  // Initialize the Eigen device
  estream = new Eigen::CudaStreamDevice(device_id);
  edevice = new Eigen::GpuDevice(estream);

  // this is the big memory allocation. Do it in stages to make sure things are aligned.
  size_t byte_count = (size_t)((mb << 10)/3) << 10;
  for(size_t i = 0; i < 3; ++i)
    pools[i] = new AlignedMemoryPool(byte_count, mem);
}

Device_GPU::~Device_GPU() {}
#endif

// TODO we should be able to configure this carefully with a configuration
// script
// CPU -- 0 params
//     -- 50mb fxs
//     -- 50mb dEdfx
Device_CPU::Device_CPU(int my_id, int mb, bool shared) :
    Device(my_id, DeviceType::CPU, &cpu_mem), shmem(mem) {
  if (shared) shmem = new SharedAllocator();
  kSCALAR_MINUSONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_MINUSONE = -1;
  kSCALAR_ONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ONE = 1;
  kSCALAR_ZERO = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ZERO = 0;

  // Initialize the Eigen device
  edevice = new Eigen::DefaultDevice;

  // this is the big memory allocation. Do it in stages to make sure things are aligned.
  size_t byte_count = (size_t)((mb << 10)/3) << 10;
  for(size_t i = 0; i < 3; ++i)
    pools[i] = new AlignedMemoryPool(byte_count, mem);
}

Device_CPU::~Device_CPU() {}

} // namespace cnn
<|endoftext|>