<commit_before>/*
 * Copyright 2015 - 2016 gtalent2@gmail.com
 *
 * 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/.
 */
#ifndef WOMBAT_FS_FILESTORE_HPP
#define WOMBAT_FS_FILESTORE_HPP

#include "_memops.hpp"
#include "_types.hpp"

namespace wombat {
namespace fs {

template<typename FsSize_t>
class FileStore {

	public:
		struct FsHeader {
			uint32_t version;
			FsSize_t rootDir = -1;
		};

		typedef FsSize_t RecordId;

	private:
		struct Inode {
			// the next Inode in memory
			FsSize_t prev, next;
			FsSize_t left, right;
			FsSize_t dataLen;
			// offsets from Inode this
			FsSize_t m_id;
			FsSize_t m_data;

			FsSize_t size();
			void setId(RecordId);
			void setData(uint8_t *data, int size);

			private:
				Inode() = default;
		};

		uint8_t *m_begin, *m_end;
		uint32_t &m_version;
		// the last Inode in the FileStore's memory chunk
		FsSize_t &m_lastRec;
		Inode *m_root;

	public:
		/**
		 * Constructor
		 * @param begin pointer to the beginning of this FileStore's memory chunk
		 * @param end pointer to the end of this FileStore's memory chunk
		 * @param error pointer to a integer return errors into
		 */
		FileStore(uint8_t *begin, uint8_t *end, Error *error = nullptr);

		/**
		 * Initializes the memory chunk of this FileStore was given.
		 * This clears the previous contents.
		 */
		void init();

		/**
		 * Writes the given data to a "file" with the given id.
		 * @param id the id of the file
		 * @param data the contents of the file
		 * @param dataLen the number of bytes data points to
		 */
		void write(RecordId id, void *data, FsSize_t dataLen);

		/**
		 * Reads the "file" at the given id. You are responsible for freeing
		 * the data when done with it.
		 * @param id id of the "file"
		 * @param data pointer to the pointer where the data is stored
		 * @param size pointer to a value that will be assigned the size of data
		 * @return 0 if read is a success
		 */
		int read(RecordId id, void *data, FsSize_t *size);

		static uint8_t version();

		static uint8_t *format(uint8_t *buffer, size_t size, bool hasDirectories);

	private:
		/**
		 * Gets the record at the given id.
		 * @param root the root node to start comparing on
		 * @param id id of the "file"
		 * @param pathLen number of characters in pathLen
		 * @return the requested Inode, if available
		 */
		Inode *getRecord(FileStore::Inode *root, RecordId id);

		/**
		 * Gets an address for a new Inode.
		 * @param size the size of the Inode
		 */
		void *alloc(FsSize_t size);

		/**
		 * Compresses all of the records into a contiguous space, starting at m_root.
		 */
		void compress();

		/**
		 * Inserts the given insertValue into the tree of the given root.
		 * If the record already exists, it replaces the old on deletes it.
		 * @return true if the record was inserted
		 */
		bool insert(Inode *root, Inode *insertValue, FsSize_t *rootParentPtr = 0);

		/**
		 * Gets the FsSize_t associated with the next Inode to be allocated.
		 * @retrun the FsSize_t associated with the next Inode to be allocated
		 */
		FsSize_t iterator();

		/**
		 * Converts an actual pointer to a FsSize_t.
		 */
		FsSize_t ptr(void *ptr);

		/**
		 * Converts a FsSize_t to an actual pointer.
		 */
		template<typename T>
		T ptr(FsSize_t ptr) {
			return (T) m_begin + ptr;
		};
};

template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::Inode::size() {
	return offsetof(FileStore::Inode, m_id) + dataLen;
}

template<typename FsSize_t>
void FileStore<FsSize_t>::Inode::setId(RecordId id) {
	this->m_id = id;
}

template<typename FsSize_t>
void FileStore<FsSize_t>::Inode::setData(uint8_t *data, int size) {
	memcpy(this + m_data, data, size);
	m_data = size;
}

// FileStore

template<typename FsSize_t>
FileStore<FsSize_t>::FileStore(uint8_t *begin, uint8_t *end, Error *error): m_version(*((uint32_t*) begin)), m_lastRec(*(FsSize_t*) (begin + sizeof(m_version))) {
	if (version() != m_version) {
		// version mismatch
		if (error) {
			*error = 1;
		}
	} else {
		// ok
		m_begin = begin;
		m_end = end;
		m_root = (Inode*) (begin + sizeof(FsSize_t));
		if (error) {
			*error = 0;
		}
	}
}

template<typename FsSize_t>
void FileStore<FsSize_t>::init() {
	memset(m_begin, 0, m_end - m_begin);
	m_version = version;
}

template<typename FsSize_t>
void FileStore<FsSize_t>::write(RecordId id, void *data, FsSize_t dataLen) {
	const FsSize_t size = offsetof(FileStore::Inode, m_id) + dataLen;
	auto rec = (Inode*) alloc(size);
	rec->dataLen = dataLen;
	insert(m_root, rec);
}

template<typename FsSize_t>
int FileStore<FsSize_t>::read(RecordId id, void *data, FsSize_t *size) {
	auto rec = getRecord(m_root, id);
	int retval = 1;
	if (rec) {
		if (size) {
			*size = rec->dataLen;
		}
		memcpy(data, ptr<uint8_t*>(rec->m_data), rec->dataLen);
		retval = 0;
	}
	return retval;
}

template<typename FsSize_t>
typename FileStore<FsSize_t>::Inode *FileStore<FsSize_t>::getRecord(FileStore::Inode *root, RecordId id) {
	auto cmp = root->m_id > id;
	FsSize_t recPt;
	if (cmp) {
		recPt = root->left;
	} else if (!cmp) {
		recPt = root->right;
	} else {
		recPt = ptr(root);
	}
	if (recPt) {
		return getRecord(ptr<Inode*>(recPt), id);
	} else {
		return ptr<Inode*>(recPt);
	}
}

template<typename FsSize_t>
void *FileStore<FsSize_t>::alloc(FsSize_t size) {
	const auto iterator = this->iterator();
	if ((iterator + size) > (uint64_t) m_end) {
		compress();
		if ((iterator + size) > (uint64_t) m_end) {
			return nullptr;
		}
	}
	ptr<Inode*>(m_lastRec)->next = iterator;

	auto rec = ptr<uint8_t*>(iterator);
	memset(rec, 0, size);
	ptr<Inode*>(iterator)->prev = m_lastRec;
	m_lastRec = iterator;
	return rec;
}

template<typename FsSize_t>
void FileStore<FsSize_t>::compress() {
	auto current = m_root;
	while (current->next) {
		auto prevEnd = current + current->size();
		current = ptr<Inode*>(current->next);
		if (prevEnd != current) {
			memcpy(prevEnd, current, current->size());
			current = prevEnd;
		}
	}
}

template<typename FsSize_t>
bool FileStore<FsSize_t>::insert(Inode *root, Inode *insertValue, FsSize_t *rootParentPtr) {
	auto cmp = root->m_id > insertValue->m_id;
	if (cmp) {
		if (root->left) {
			return insert(ptr<Inode*>(root->left), insertValue, &root->left);
		} else {
			root->left = ((uint8_t*) insertValue) - m_begin;
			return true;
		}
	} else if (!cmp) {
		if (root->right) {
			return insert(ptr<Inode*>(root->right), insertValue, &root->right);
		} else {
			root->right = ((uint8_t*) insertValue) - m_begin;
			return true;
		}
	} else {
		auto ivAddr = ((uint8_t*) insertValue) - m_begin;
		if (root->prev) {
			ptr<Inode*>(root->prev)->next = ivAddr;
		}
		if (root->next) {
			ptr<Inode*>(root->next)->prev = ivAddr;
		}
		if (rootParentPtr) {
			*rootParentPtr = ivAddr;
		}
		return true;
	}
	return false;
}

template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::iterator() {
	return m_lastRec + ((Inode*) m_begin + m_lastRec)->size();
}

template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::ptr(void *ptr) {
	return ((uint8_t*) ptr) - m_begin;
}

template<typename FsSize_t>
uint8_t FileStore<FsSize_t>::version() {
	return 0;
};

template<typename FsSize_t>
uint8_t *FileStore<FsSize_t>::format(uint8_t *buffer, size_t size, bool hasDirectories) {
	auto retval = (typename FileStore<FsSize_t>::FsHeader*) buffer;
	retval->version = FileStore<FsSize_t>::version();
	return (uint8_t*) retval;
}

typedef FileStore<uint16_t> FileStore16;
typedef FileStore<uint32_t> FileStore32;
typedef FileStore<uint64_t> FileStore64;

}
}

#endif
<commit_msg>Renamed RecordId to InodeId.<commit_after>/*
 * Copyright 2015 - 2016 gtalent2@gmail.com
 *
 * 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/.
 */
#ifndef WOMBAT_FS_FILESTORE_HPP
#define WOMBAT_FS_FILESTORE_HPP

#include "_memops.hpp"
#include "_types.hpp"

namespace wombat {
namespace fs {

template<typename FsSize_t>
class FileStore {

	public:
		struct FsHeader {
			uint32_t version;
			FsSize_t rootDir = -1;
			bool insertLeft = false; // crude tree balancing mechanism
		};

		typedef uint16_t InodeId_t;

	private:
		struct Inode {
			// the next Inode in memory
			FsSize_t prev, next;
			FsSize_t left, right;
			FsSize_t dataLen;
			// offsets from Inode this
			FsSize_t m_id;
			FsSize_t m_data;

			FsSize_t size();
			void setId(InodeId_t);
			void setData(uint8_t *data, int size);

			private:
				Inode() = default;
		};

		uint8_t *m_begin, *m_end;
		uint32_t &m_version;
		// the last Inode in the FileStore's memory chunk
		FsSize_t &m_lastRec;
		Inode *m_root;

	public:
		/**
		 * Constructor
		 * @param begin pointer to the beginning of this FileStore's memory chunk
		 * @param end pointer to the end of this FileStore's memory chunk
		 * @param error pointer to a integer return errors into
		 */
		FileStore(uint8_t *begin, uint8_t *end, Error *error = nullptr);

		/**
		 * Initializes the memory chunk of this FileStore was given.
		 * This clears the previous contents.
		 */
		void init();

		/**
		 * Writes the given data to a "file" with the given id.
		 * @param id the id of the file
		 * @param data the contents of the file
		 * @param dataLen the number of bytes data points to
		 */
		void write(void *data, FsSize_t dataLen);

		/**
		 * Writes the given data to a "file" with the given id.
		 * @param id the id of the file
		 * @param data the contents of the file
		 * @param dataLen the number of bytes data points to
		 */
		void write(InodeId_t id, void *data, FsSize_t dataLen);

		/**
		 * Reads the "file" at the given id. You are responsible for freeing
		 * the data when done with it.
		 * @param id id of the "file"
		 * @param data pointer to the pointer where the data is stored
		 * @param size pointer to a value that will be assigned the size of data
		 * @return 0 if read is a success
		 */
		int read(InodeId_t id, void *data, FsSize_t *size);

		static uint8_t version();

		static uint8_t *format(uint8_t *buffer, size_t size, bool hasDirectories);

	private:
		/**
		 * Gets the header section of the file system.
		 * @return the header section of the file system.
		 */
		FsHeader *getHeader();

		/**
		 * Gets the record at the given id.
		 * @param root the root node to start comparing on
		 * @param id id of the "file"
		 * @param pathLen number of characters in pathLen
		 * @return the requested Inode, if available
		 */
		Inode *getRecord(FileStore::Inode *root, InodeId_t id);

		/**
		 * Gets an address for a new Inode.
		 * @param size the size of the Inode
		 */
		void *alloc(FsSize_t size);

		/**
		 * Compresses all of the records into a contiguous space, starting at m_root.
		 */
		void compress();

		/**
		 * Inserts the given insertValue into the tree of the given root.
		 * If the record already exists, it replaces the old on deletes it.
		 * @return true if the record was inserted
		 */
		bool insert(Inode *root, Inode *insertValue, FsSize_t *rootParentPtr = 0);

		/**
		 * Gets the FsSize_t associated with the next Inode to be allocated.
		 * @retrun the FsSize_t associated with the next Inode to be allocated
		 */
		FsSize_t iterator();

		/**
		 * Converts an actual pointer to a FsSize_t.
		 */
		FsSize_t ptr(void *ptr);

		/**
		 * Converts a FsSize_t to an actual pointer.
		 */
		template<typename T>
		T ptr(FsSize_t ptr) {
			return (T) m_begin + ptr;
		};
};

template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::Inode::size() {
	return offsetof(FileStore::Inode, m_id) + dataLen;
}

template<typename FsSize_t>
void FileStore<FsSize_t>::Inode::setId(InodeId_t id) {
	this->m_id = id;
}

template<typename FsSize_t>
void FileStore<FsSize_t>::Inode::setData(uint8_t *data, int size) {
	memcpy(this + m_data, data, size);
	m_data = size;
}

// FileStore

template<typename FsSize_t>
FileStore<FsSize_t>::FileStore(uint8_t *begin, uint8_t *end, Error *error): m_version(*((uint32_t*) begin)), m_lastRec(*(FsSize_t*) (begin + sizeof(m_version))) {
	if (version() != m_version) {
		// version mismatch
		if (error) {
			*error = 1;
		}
	} else {
		// ok
		m_begin = begin;
		m_end = end;
		m_root = (Inode*) (begin + sizeof(FsSize_t));
		if (error) {
			*error = 0;
		}
	}
}

template<typename FsSize_t>
void FileStore<FsSize_t>::init() {
	memset(m_begin, 0, m_end - m_begin);
	m_version = version();
}

template<typename FsSize_t>
void FileStore<FsSize_t>::write(InodeId_t id, void *data, FsSize_t dataLen) {
	const FsSize_t size = offsetof(Inode, m_id) + dataLen;
	auto rec = (Inode*) alloc(size);
	rec->dataLen = dataLen;
	insert(m_root, rec);
}

template<typename FsSize_t>
int FileStore<FsSize_t>::read(InodeId_t id, void *data, FsSize_t *size) {
	auto rec = getRecord(m_root, id);
	int retval = 1;
	if (rec) {
		if (size) {
			*size = rec->dataLen;
		}
		memcpy(data, ptr<uint8_t*>(rec->m_data), rec->dataLen);
		retval = 0;
	}
	return retval;
}

template<typename FsSize_t>
typename FileStore<FsSize_t>::FsHeader *FileStore<FsSize_t>::getHeader() {
	return (FsHeader*) m_begin;
}

template<typename FsSize_t>
typename FileStore<FsSize_t>::Inode *FileStore<FsSize_t>::getRecord(FileStore::Inode *root, InodeId_t id) {
	auto cmp = root->m_id > id;
	FsSize_t recPt;
	if (cmp) {
		recPt = root->left;
	} else if (!cmp) {
		recPt = root->right;
	} else {
		recPt = ptr(root);
	}
	if (recPt) {
		return getRecord(ptr<Inode*>(recPt), id);
	} else {
		return ptr<Inode*>(recPt);
	}
}

template<typename FsSize_t>
void *FileStore<FsSize_t>::alloc(FsSize_t size) {
	const auto iterator = this->iterator();
	if ((iterator + size) > (uint64_t) m_end) {
		compress();
		if ((iterator + size) > (uint64_t) m_end) {
			return nullptr;
		}
	}
	ptr<Inode*>(m_lastRec)->next = iterator;

	auto rec = ptr<uint8_t*>(iterator);
	memset(rec, 0, size);
	ptr<Inode*>(iterator)->prev = m_lastRec;
	m_lastRec = iterator;
	return rec;
}

template<typename FsSize_t>
void FileStore<FsSize_t>::compress() {
	auto current = m_root;
	while (current->next) {
		auto prevEnd = current + current->size();
		current = ptr<Inode*>(current->next);
		if (prevEnd != current) {
			memcpy(prevEnd, current, current->size());
			current = prevEnd;
		}
	}
}

template<typename FsSize_t>
bool FileStore<FsSize_t>::insert(Inode *root, Inode *insertValue, FsSize_t *rootParentPtr) {
	auto cmp = root->m_id > insertValue->m_id;
	if (cmp) {
		if (root->left) {
			return insert(ptr<Inode*>(root->left), insertValue, &root->left);
		} else {
			root->left = ((uint8_t*) insertValue) - m_begin;
			return true;
		}
	} else if (!cmp) {
		if (root->right) {
			return insert(ptr<Inode*>(root->right), insertValue, &root->right);
		} else {
			root->right = ((uint8_t*) insertValue) - m_begin;
			return true;
		}
	} else {
		auto ivAddr = ((uint8_t*) insertValue) - m_begin;
		if (root->prev) {
			ptr<Inode*>(root->prev)->next = ivAddr;
		}
		if (root->next) {
			ptr<Inode*>(root->next)->prev = ivAddr;
		}
		if (rootParentPtr) {
			*rootParentPtr = ivAddr;
		}
		return true;
	}
	return false;
}

template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::iterator() {
	return m_lastRec + ((Inode*) m_begin + m_lastRec)->size();
}

template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::ptr(void *ptr) {
	return ((uint8_t*) ptr) - m_begin;
}

template<typename FsSize_t>
uint8_t FileStore<FsSize_t>::version() {
	return 0;
};

template<typename FsSize_t>
uint8_t *FileStore<FsSize_t>::format(uint8_t *buffer, size_t size, bool hasDirectories) {
	auto retval = (typename FileStore<FsSize_t>::FsHeader*) buffer;
	retval->version = FileStore<FsSize_t>::version();
	return (uint8_t*) retval;
}

typedef FileStore<uint16_t> FileStore16;
typedef FileStore<uint32_t> FileStore32;
typedef FileStore<uint64_t> FileStore64;

}
}

#endif
<|endoftext|>


<commit_before>#include "mfem.hpp"
#include "catch.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace pa_kernels
{

double zero_field(const Vector &x)
{
   return 0.0;
}

void solenoidal_field2d(const Vector &x, Vector &u)
{
   u(0) = x(1);
   u(1) = -x(0);
}

void non_solenoidal_field2d(const Vector &x, Vector &u)
{
   u(0) = x(0) * x(1);
   u(1) = -x(0) + x(1);
}

double div_non_solenoidal_field2d(const Vector &x)
{
   return 1.0 + x(1);
}

void solenoidal_field3d(const Vector &x, Vector &u)
{
   double xi = x(0);
   double yi = x(1);
   double zi = x(2);

   u(0) = -cos(zi) * sin(xi);
   u(1) = -cos(xi) * cos(zi);
   u(2) = cos(xi) * sin(yi) + cos(xi) * sin(zi);
}

void non_solenoidal_field3d(const Vector &x, Vector &u)
{
   double xi = x(0);
   double yi = x(1);
   double zi = x(2);

   u(0) = cos(xi) * cos(yi);
   u(1) = sin(xi) * sin(zi);
   u(2) = cos(zi) * sin(xi);
}

double div_non_solenoidal_field3d(const Vector &x)
{
   double xi = x(0);
   double yi = x(1);
   double zi = x(2);
   return -cos(yi)*sin(xi)-sin(xi)*sin(zi);
}

double pa_divergence_testnd(int dim, void(*f1)(const Vector&, Vector&),
                            double(*divf1)(const Vector&))
{
   Mesh *mesh = nullptr;
   if (dim == 2)
   {
      mesh = new Mesh(2, 2, Element::QUADRILATERAL, 0, 1.0, 1.0);
   }
   if (dim == 3)
   {
      mesh = new Mesh(2, 2, 2, Element::HEXAHEDRON, 0, 1.0, 1.0, 1.0);
   }

   int order = 4;

   // Vector valued
   H1_FECollection fec1(order, dim);
   FiniteElementSpace fes1(mesh, &fec1, dim);

   // Scalar
   H1_FECollection fec2(order, dim);
   FiniteElementSpace fes2(mesh, &fec2);

   GridFunction field(&fes1), field2(&fes2);

   MixedBilinearForm dform(&fes1, &fes2);
   dform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
   dform.AddDomainIntegrator(new DivergenceIntegrator);
   dform.Assemble();

   // Project u = f1
   VectorFunctionCoefficient fcoeff1(dim, f1);
   field.ProjectCoefficient(fcoeff1);

   // Check if div(u) = divf1
   dform.Mult(field, field2);
   FunctionCoefficient fcoeff2(divf1);
   LinearForm lf(&fes2);
   lf.AddDomainIntegrator(new DomainLFIntegrator(fcoeff2));
   lf.Assemble();
   field2 -= lf;

   delete mesh;

   return field2.Norml2();
}

double testfunc(const Vector &x)
{
   double r = cos(x(0)) + sin(x(1));
   if (x.Size() == 3)
   {
      r += cos(x(2));
   }
   return r;
}

void grad_testfunc(const Vector &x, Vector &u)
{
   u(0) = -sin(x(0));
   u(1) = cos(x(1));
   if (x.Size() == 3)
   {
      u(2) = -sin(x(2));
   }
}

double pa_gradient_testnd(int dim, double(*f1)(const Vector&),
                          void(*gradf1)(const Vector &, Vector &))
{

   Mesh *mesh = nullptr;
   if (dim == 2)
   {
      mesh = new Mesh(2, 2, Element::QUADRILATERAL, 0, 1.0, 1.0);
   }
   if (dim == 3)
   {
      mesh = new Mesh(2, 2, 2, Element::HEXAHEDRON, 0, 1.0, 1.0, 1.0);
   }

   int order = 4;

   // Scalar
   H1_FECollection fec1(order, dim);
   FiniteElementSpace fes1(mesh, &fec1);

   // Vector valued
   H1_FECollection fec2(order, dim);
   FiniteElementSpace fes2(mesh, &fec2, dim);

   GridFunction field(&fes1), field2(&fes2);

   MixedBilinearForm gform(&fes1, &fes2);
   gform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
   gform.AddDomainIntegrator(new GradientIntegrator);
   gform.Assemble();

   // Project u = f1
   FunctionCoefficient fcoeff1(f1);
   field.ProjectCoefficient(fcoeff1);

   // Check if grad(u) = gradf1
   gform.Mult(field, field2);
   VectorFunctionCoefficient fcoeff2(dim, gradf1);
   LinearForm lf(&fes2);
   lf.AddDomainIntegrator(new VectorDomainLFIntegrator(fcoeff2));
   lf.Assemble();
   field2 -= lf;

   delete mesh;

   return field2.Norml2();
}

TEST_CASE("PA Divergence", "[PartialAssembly]")
{
   SECTION("2D")
   {
      // Check if div([y, -x]) == 0
      REQUIRE(pa_divergence_testnd(2, solenoidal_field2d, zero_field) == Approx(0.0));

      // Check if div([x*y, -x+y]) == 1 + y
      REQUIRE(pa_divergence_testnd(2, non_solenoidal_field2d,
                                   div_non_solenoidal_field2d) == Approx(0.0));
   }

   SECTION("3D")
   {
      // Check if div([-Cos[z] Sin[x], -Cos[x] Cos[z], Cos[x] Sin[y] + Cos[x] Sin[z]) == 0
      REQUIRE(pa_divergence_testnd(3, solenoidal_field3d, zero_field) == Approx(0.0));

      // Check if div([Cos[x] Cos[y], Sin[x] Sin[z], Cos[z] Sin[x]]) == -Cos[y] Sin[x] - Sin[x] Sin[z]
      REQUIRE(pa_divergence_testnd(3, non_solenoidal_field3d,
                                   div_non_solenoidal_field3d) == Approx(0.0));
   }
}

TEST_CASE("PA Gradient", "[PartialAssembly]")
{
   SECTION("2D")
   {
      // Check if grad(Cos[x] + Sin[y]) == [-Sin[x], Cos[y]]
      REQUIRE(pa_gradient_testnd(2, testfunc, grad_testfunc) == Approx(0.0));
   }
   SECTION("3D")
   {
      // Check if grad(Cos[x] + Sin[y] + Cos[z]) == [-Sin[x], Cos[y], -Sin[z]]
      REQUIRE(pa_gradient_testnd(3, testfunc, grad_testfunc) == Approx(0.0));
   }
}

}
<commit_msg>Update tests for renaming and formatting<commit_after>#include "catch.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace pa_kernels
{
double zero_field(const Vector &x)
{
   return 0.0;
}

void solenoidal_field2d(const Vector &x, Vector &u)
{
   u(0) = x(1);
   u(1) = -x(0);
}

void non_solenoidal_field2d(const Vector &x, Vector &u)
{
   u(0) = x(0) * x(1);
   u(1) = -x(0) + x(1);
}

double div_non_solenoidal_field2d(const Vector &x)
{
   return 1.0 + x(1);
}

void solenoidal_field3d(const Vector &x, Vector &u)
{
   double xi = x(0);
   double yi = x(1);
   double zi = x(2);

   u(0) = -cos(zi) * sin(xi);
   u(1) = -cos(xi) * cos(zi);
   u(2) = cos(xi) * sin(yi) + cos(xi) * sin(zi);
}

void non_solenoidal_field3d(const Vector &x, Vector &u)
{
   double xi = x(0);
   double yi = x(1);
   double zi = x(2);

   u(0) = cos(xi) * cos(yi);
   u(1) = sin(xi) * sin(zi);
   u(2) = cos(zi) * sin(xi);
}

double div_non_solenoidal_field3d(const Vector &x)
{
   double xi = x(0);
   double yi = x(1);
   double zi = x(2);
   return -cos(yi) * sin(xi) - sin(xi) * sin(zi);
}

double pa_divergence_testnd(int dim,
                            void (*f1)(const Vector &, Vector &),
                            double (*divf1)(const Vector &))
{
   Mesh *mesh = nullptr;
   if (dim == 2)
   {
      mesh = new Mesh(2, 2, Element::QUADRILATERAL, 0, 1.0, 1.0);
   }
   if (dim == 3)
   {
      mesh = new Mesh(2, 2, 2, Element::HEXAHEDRON, 0, 1.0, 1.0, 1.0);
   }

   int order = 4;

   // Vector valued
   H1_FECollection fec1(order, dim);
   FiniteElementSpace fes1(mesh, &fec1, dim);

   // Scalar
   H1_FECollection fec2(order, dim);
   FiniteElementSpace fes2(mesh, &fec2);

   GridFunction field(&fes1), field2(&fes2);

   MixedBilinearForm dform(&fes1, &fes2);
   dform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
   dform.AddDomainIntegrator(new VectorDivergenceIntegrator);
   dform.Assemble();

   // Project u = f1
   VectorFunctionCoefficient fcoeff1(dim, f1);
   field.ProjectCoefficient(fcoeff1);

   // Check if div(u) = divf1
   dform.Mult(field, field2);
   FunctionCoefficient fcoeff2(divf1);
   LinearForm lf(&fes2);
   lf.AddDomainIntegrator(new DomainLFIntegrator(fcoeff2));
   lf.Assemble();
   field2 -= lf;

   delete mesh;

   return field2.Norml2();
}

double testfunc(const Vector &x)
{
   double r = cos(x(0)) + sin(x(1));
   if (x.Size() == 3)
   {
      r += cos(x(2));
   }
   return r;
}

void grad_testfunc(const Vector &x, Vector &u)
{
   u(0) = -sin(x(0));
   u(1) = cos(x(1));
   if (x.Size() == 3)
   {
      u(2) = -sin(x(2));
   }
}

double pa_gradient_testnd(int dim,
                          double (*f1)(const Vector &),
                          void (*gradf1)(const Vector &, Vector &))
{
   Mesh *mesh = nullptr;
   if (dim == 2)
   {
      mesh = new Mesh(2, 2, Element::QUADRILATERAL, 0, 1.0, 1.0);
   }
   if (dim == 3)
   {
      mesh = new Mesh(2, 2, 2, Element::HEXAHEDRON, 0, 1.0, 1.0, 1.0);
   }

   int order = 4;

   // Scalar
   H1_FECollection fec1(order, dim);
   FiniteElementSpace fes1(mesh, &fec1);

   // Vector valued
   H1_FECollection fec2(order, dim);
   FiniteElementSpace fes2(mesh, &fec2, dim);

   GridFunction field(&fes1), field2(&fes2);

   MixedBilinearForm gform(&fes1, &fes2);
   gform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
   gform.AddDomainIntegrator(new GradientIntegrator);
   gform.Assemble();

   // Project u = f1
   FunctionCoefficient fcoeff1(f1);
   field.ProjectCoefficient(fcoeff1);

   // Check if grad(u) = gradf1
   gform.Mult(field, field2);
   VectorFunctionCoefficient fcoeff2(dim, gradf1);
   LinearForm lf(&fes2);
   lf.AddDomainIntegrator(new VectorDomainLFIntegrator(fcoeff2));
   lf.Assemble();
   field2 -= lf;

   delete mesh;

   return field2.Norml2();
}

TEST_CASE("PA VectorDivergence", "[PartialAssembly]")
{
   SECTION("2D")
   {
      // Check if div([y, -x]) == 0
      REQUIRE(pa_divergence_testnd(2, solenoidal_field2d, zero_field)
              == Approx(0.0));

      // Check if div([x*y, -x+y]) == 1 + y
      REQUIRE(pa_divergence_testnd(2,
                                   non_solenoidal_field2d,
                                   div_non_solenoidal_field2d)
              == Approx(0.0));
   }

   SECTION("3D")
   {
      // Check if
      // div([-Cos[z] Sin[x],
      //      -Cos[x] Cos[z],
      //       Cos[x] Sin[y] + Cos[x] Sin[z]) == 0
      REQUIRE(pa_divergence_testnd(3, solenoidal_field3d, zero_field)
              == Approx(0.0));

      // Check if
      // div([Cos[x] Cos[y],
      //      Sin[x] Sin[z],
      //      Cos[z] Sin[x]]) == -Cos[y] Sin[x] - Sin[x] Sin[z]
      REQUIRE(pa_divergence_testnd(3,
                                   non_solenoidal_field3d,
                                   div_non_solenoidal_field3d)
              == Approx(0.0));
   }
}

TEST_CASE("PA Gradient", "[PartialAssembly]")
{
   SECTION("2D")
   {
      // Check if grad(Cos[x] + Sin[y]) == [-Sin[x], Cos[y]]
      REQUIRE(pa_gradient_testnd(2, testfunc, grad_testfunc) == Approx(0.0));
   }
   SECTION("3D")
   {
      // Check if grad(Cos[x] + Sin[y] + Cos[z]) == [-Sin[x], Cos[y], -Sin[z]]
      REQUIRE(pa_gradient_testnd(3, testfunc, grad_testfunc) == Approx(0.0));
   }
}

} // namespace pa_kernels
<|endoftext|>


<commit_before>/********** tell emacs we use -*- c++ -*- style comments *******************
 $Revision: 1.3 $  $Author: trey $  $Date: 2005-10-28 03:50:32 $

 @file    testProblemRepresentation.cc
 @brief   No brief

 Copyright (c) 2002-2005, Trey Smith
 All rights reserved.

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

 * The software may not be sold or incorporated into a commercial
   product without specific prior written permission.
 * The above copyright notice and this permission notice shall be
   included in all copies or substantial portions of the software.

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

 ***************************************************************************/

#include "Pomdp.h"
#include "MatrixUtils.h"

using namespace std;
using namespace MatrixUtils;

int main(int argc, char** argv) {
  init_matrix_utils();

  Pomdp problem;
  problem.readFromFile( argv[1], /* use_fast_parser = */ false );

  write_to_file(problem.R,"R.dat");

  FOR (i, problem.numStates) {
    if (problem.isTerminalState[i]) {
      cout << "E: " << i << endl;
    }
  }

#if 0
  cout << "numStates = " << problem.numStates << endl;
  cout << "T.size = " << problem.T[4].size1()
       << " " << problem.T[4].size2() << endl;

  timeval startTime, endTime;
  belief_vector result(problem.numStates);
  bmatrix& T = problem.T[4];
  belief_vector& b0 = problem.initialBelief;
  dvector tmp(problem.numStates);

  gettimeofday(&startTime,0);
  for (int i=0; i < 10; i++) {
    //noalias(result) = prod( T, b0 );
    axpy_prod( T, b0, tmp, true );
    result = tmp;
  }
  gettimeofday(&endTime,0);

  cout << "multiplies: elapsed time = "
       << ((endTime.tv_sec - startTime.tv_sec)
	   + 1e-6*(endTime.tv_usec - startTime.tv_usec))
       << endl;

  const char* fname = "result_tp.dat";
  ofstream out(fname);
  if (!out) {
    cerr << "ERROR: couldn't open " << fname << " for writing: "
	 << strerror(errno) << endl;
    exit(EXIT_FAILURE);
  }
  out << problem.numStates << endl;
  FOR (i, problem.numStates) {
    out << result[i] << endl;
  }
  out.close();
#endif

  return 0;
}

/***************************************************************************
 * REVISION HISTORY:
 * $Log: not supported by cvs2svn $
 * Revision 1.2  2005/10/28 02:51:41  trey
 * added copyright headers
 *
 *
 ***************************************************************************/
<commit_msg>fixed missing "using namespace pomdp"<commit_after>/********** tell emacs we use -*- c++ -*- style comments *******************
 $Revision: 1.4 $  $Author: trey $  $Date: 2005-11-29 04:44:15 $

 @file    testProblemRepresentation.cc
 @brief   No brief

 Copyright (c) 2002-2005, Trey Smith
 All rights reserved.

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

 * The software may not be sold or incorporated into a commercial
   product without specific prior written permission.
 * The above copyright notice and this permission notice shall be
   included in all copies or substantial portions of the software.

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

 ***************************************************************************/

#include "Pomdp.h"
#include "MatrixUtils.h"

using namespace std;
using namespace MatrixUtils;
using namespace pomdp;

int main(int argc, char** argv) {
  init_matrix_utils();

  Pomdp problem;
  problem.readFromFile( argv[1], /* use_fast_parser = */ false );

  write_to_file(problem.R,"R.dat");

  FOR (i, problem.numStates) {
    if (problem.isTerminalState[i]) {
      cout << "E: " << i << endl;
    }
  }

#if 0
  cout << "numStates = " << problem.numStates << endl;
  cout << "T.size = " << problem.T[4].size1()
       << " " << problem.T[4].size2() << endl;

  timeval startTime, endTime;
  belief_vector result(problem.numStates);
  bmatrix& T = problem.T[4];
  belief_vector& b0 = problem.initialBelief;
  dvector tmp(problem.numStates);

  gettimeofday(&startTime,0);
  for (int i=0; i < 10; i++) {
    //noalias(result) = prod( T, b0 );
    axpy_prod( T, b0, tmp, true );
    result = tmp;
  }
  gettimeofday(&endTime,0);

  cout << "multiplies: elapsed time = "
       << ((endTime.tv_sec - startTime.tv_sec)
	   + 1e-6*(endTime.tv_usec - startTime.tv_usec))
       << endl;

  const char* fname = "result_tp.dat";
  ofstream out(fname);
  if (!out) {
    cerr << "ERROR: couldn't open " << fname << " for writing: "
	 << strerror(errno) << endl;
    exit(EXIT_FAILURE);
  }
  out << problem.numStates << endl;
  FOR (i, problem.numStates) {
    out << result[i] << endl;
  }
  out.close();
#endif

  return 0;
}

/***************************************************************************
 * REVISION HISTORY:
 * $Log: not supported by cvs2svn $
 * Revision 1.3  2005/10/28 03:50:32  trey
 * simplified license
 *
 * Revision 1.2  2005/10/28 02:51:41  trey
 * added copyright headers
 *
 *
 ***************************************************************************/
<|endoftext|>


<commit_before>#ifndef SILICIUM_REACTIVE_PTR_OBSERVABLE_HPP
#define SILICIUM_REACTIVE_PTR_OBSERVABLE_HPP

#include <silicium/observer.hpp>
#include <silicium/override.hpp>
#include <silicium/config.hpp>
#include <silicium/virtualized_observable.hpp>
#include <boost/config.hpp>
#include <memory>
#include <cassert>

namespace Si
{
	template <class Element, class Ptr>
	struct ptr_observable
	{
		typedef Element element_type;

		BOOST_DEFAULTED_FUNCTION(ptr_observable(), {})

		explicit ptr_observable(Ptr content)
			: content(std::move(content))
		{
		}

#ifdef _MSC_VER
		ptr_observable(ptr_observable &&other)
			: content(std::move(other.content))
		{
		}

		ptr_observable &operator = (ptr_observable &&other)
		{
			content = std::move(other.content);
			return *this;
		}

		ptr_observable(ptr_observable const &other)
			: content(other.content)
		{
		}

		ptr_observable &operator = (ptr_observable const &other)
		{
			content = other.content;
			return *this;
		}
#endif

		bool empty() const BOOST_NOEXCEPT
		{
			return !content;
		}

		void async_get_one(observer<element_type> &receiver)
		{
			assert(content);
			return content->async_get_one(receiver);
		}

	private:

		Ptr content;
	};

	template <class Element>
	using unique_observable = ptr_observable<Element, std::unique_ptr<observable<Element>>>;

	template <class Element>
	using shared_observable = ptr_observable<Element, std::shared_ptr<observable<Element>>>;

	template <class Element, class Content>
	auto wrap(Content &&content) -> ptr_observable<Element, std::shared_ptr<typename std::decay<Content>::type>>
	{
		return ptr_observable<Element, std::shared_ptr<typename std::decay<Content>::type>>(std::make_shared<typename std::decay<Content>::type>(std::forward<Content>(content)));
	}

	template <class Observable, class ...Args>
	auto make_wrapped(Args &&...args) -> ptr_observable<typename Observable::element_type, std::shared_ptr<Observable>>
	{
		typedef typename Observable::element_type element_type;
		typedef std::shared_ptr<Observable> ptr_type;
		return ptr_observable<element_type, ptr_type>(std::make_shared<Observable>(std::forward<Args>(args)...));
	}

	template <class Input>
	auto erase_unique(Input &&input) -> Si::unique_observable<typename std::decay<Input>::type::element_type>
	{
		using clean_input = typename std::decay<Input>::type;
		using element_type = typename clean_input::element_type;
		return Si::unique_observable<element_type>(
					Si::make_unique<Si::virtualized_observable<clean_input>>(
						std::forward<Input>(input)
					)
				);
	}

	template <class Input>
	auto erase_shared(Input &&input) -> Si::shared_observable<typename std::decay<Input>::type::element_type>
	{
		using clean_input = typename std::decay<Input>::type;
		using element_type = typename clean_input::element_type;
		return Si::shared_observable<element_type>(
					std::make_shared<Si::virtualized_observable<clean_input>>(
						std::forward<Input>(input)
					)
				);
	}
}

#endif
<commit_msg>remove wrap (use erase_shared instead)<commit_after>#ifndef SILICIUM_REACTIVE_PTR_OBSERVABLE_HPP
#define SILICIUM_REACTIVE_PTR_OBSERVABLE_HPP

#include <silicium/observer.hpp>
#include <silicium/override.hpp>
#include <silicium/config.hpp>
#include <silicium/virtualized_observable.hpp>
#include <boost/config.hpp>
#include <memory>
#include <cassert>

namespace Si
{
	template <class Element, class Ptr>
	struct ptr_observable
	{
		typedef Element element_type;

		BOOST_DEFAULTED_FUNCTION(ptr_observable(), {})

		explicit ptr_observable(Ptr content)
			: content(std::move(content))
		{
		}

#ifdef _MSC_VER
		ptr_observable(ptr_observable &&other)
			: content(std::move(other.content))
		{
		}

		ptr_observable &operator = (ptr_observable &&other)
		{
			content = std::move(other.content);
			return *this;
		}

		ptr_observable(ptr_observable const &other)
			: content(other.content)
		{
		}

		ptr_observable &operator = (ptr_observable const &other)
		{
			content = other.content;
			return *this;
		}
#endif

		bool empty() const BOOST_NOEXCEPT
		{
			return !content;
		}

		void async_get_one(observer<element_type> &receiver)
		{
			assert(content);
			return content->async_get_one(receiver);
		}

	private:

		Ptr content;
	};

	template <class Element>
	using unique_observable = ptr_observable<Element, std::unique_ptr<observable<Element>>>;

	template <class Element>
	using shared_observable = ptr_observable<Element, std::shared_ptr<observable<Element>>>;

	template <class Observable, class ...Args>
	auto make_wrapped(Args &&...args) -> ptr_observable<typename Observable::element_type, std::shared_ptr<Observable>>
	{
		typedef typename Observable::element_type element_type;
		typedef std::shared_ptr<Observable> ptr_type;
		return ptr_observable<element_type, ptr_type>(std::make_shared<Observable>(std::forward<Args>(args)...));
	}

	template <class Input>
	auto erase_unique(Input &&input) -> Si::unique_observable<typename std::decay<Input>::type::element_type>
	{
		using clean_input = typename std::decay<Input>::type;
		using element_type = typename clean_input::element_type;
		return Si::unique_observable<element_type>(
					Si::make_unique<Si::virtualized_observable<clean_input>>(
						std::forward<Input>(input)
					)
				);
	}

	template <class Input>
	auto erase_shared(Input &&input) -> Si::shared_observable<typename std::decay<Input>::type::element_type>
	{
		using clean_input = typename std::decay<Input>::type;
		using element_type = typename clean_input::element_type;
		return Si::shared_observable<element_type>(
					std::make_shared<Si::virtualized_observable<clean_input>>(
						std::forward<Input>(input)
					)
				);
	}
}

#endif
<|endoftext|>


<commit_before>/*
* Montgomery Exponentiation
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/internal/def_powm.h>
#include <botan/numthry.h>
#include <botan/internal/mp_core.h>

namespace Botan {

/*
* Set the exponent
*/
void Montgomery_Exponentiator::set_exponent(const BigInt& exp)
   {
   m_exp = exp;
   m_exp_bits = exp.bits();
   }

/*
* Set the base
*/
void Montgomery_Exponentiator::set_base(const BigInt& base)
   {
   m_window_bits = Power_Mod::window_bits(m_exp.bits(), base.bits(), m_hints);

   m_g.resize((1 << m_window_bits) - 1);

   secure_vector<word> z(2 * (m_mod_words + 1));
   secure_vector<word> workspace(z.size());

   m_g[0] = (base >= m_modulus) ? (base % m_modulus) : base;

   bigint_monty_mul(&z[0], z.size(),
                    m_g[0].data(), m_g[0].size(), m_g[0].sig_words(),
                    m_R2_mod.data(), m_R2_mod.size(), m_R2_mod.sig_words(),
                    m_modulus.data(), m_mod_words, m_mod_prime,
                    &workspace[0]);

   m_g[0].assign(&z[0], m_mod_words + 1);

   const BigInt& x = m_g[0];
   const size_t x_sig = x.sig_words();

   for(size_t i = 1; i != m_g.size(); ++i)
      {
      const BigInt& y = m_g[i-1];
      const size_t y_sig = y.sig_words();

      zeroise(z);
      bigint_monty_mul(&z[0], z.size(),
                       x.data(), x.size(), x_sig,
                       y.data(), y.size(), y_sig,
                       m_modulus.data(), m_mod_words, m_mod_prime,
                       &workspace[0]);

      m_g[i].assign(&z[0], m_mod_words + 1);
      }
   }

/*
* Compute the result
*/
BigInt Montgomery_Exponentiator::execute() const
   {
   const size_t exp_nibbles = (m_exp_bits + m_window_bits - 1) / m_window_bits;

   BigInt x = m_R_mod;
   secure_vector<word> z(2 * (m_mod_words + 1));
   secure_vector<word> workspace(2 * (m_mod_words + 1));

   for(size_t i = exp_nibbles; i > 0; --i)
      {
      for(size_t k = 0; k != m_window_bits; ++k)
         {
         zeroise(z);

         bigint_monty_sqr(&z[0], z.size(),
                          x.data(), x.size(), x.sig_words(),
                          m_modulus.data(), m_mod_words, m_mod_prime,
                          &workspace[0]);

         x.assign(&z[0], m_mod_words + 1);
         }

      if(u32bit nibble = m_exp.get_substring(m_window_bits*(i-1), m_window_bits))
         {
         const BigInt& y = m_g[nibble-1];

         zeroise(z);
         bigint_monty_mul(&z[0], z.size(),
                          x.data(), x.size(), x.sig_words(),
                          y.data(), y.size(), y.sig_words(),
                          m_modulus.data(), m_mod_words, m_mod_prime,
                          &workspace[0]);

         x.assign(&z[0], m_mod_words + 1);
         }
      }

   x.get_reg().resize(2*m_mod_words+1);

   bigint_monty_redc(&x[0], x.size(),
                     m_modulus.data(), m_mod_words, m_mod_prime,
                     &workspace[0]);

   x.get_reg().resize(m_mod_words+1);

   return x;
   }

/*
* Montgomery_Exponentiator Constructor
*/
Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod,
                                                   Power_Mod::Usage_Hints hints)
   {
   // Montgomery reduction only works for positive odd moduli
   if(!mod.is_positive() || mod.is_even())
      throw Invalid_Argument("Montgomery_Exponentiator: invalid modulus");

   m_window_bits = 0;
   m_hints = hints;
   m_modulus = mod;

   m_mod_words = m_modulus.sig_words();

   const BigInt b = BigInt(1) << BOTAN_MP_WORD_BITS;
   m_mod_prime = (b - inverse_mod(m_modulus.word_at(0), b)).word_at(0);

   const BigInt r(BigInt::Power2, m_mod_words * BOTAN_MP_WORD_BITS);
   m_R_mod = r % m_modulus;
   m_R2_mod = (m_R_mod * m_R_mod) % m_modulus;
   }

}
<commit_msg>Use the extended Euclidean algorithm for computing the inverse for Montgomery exponentiation as except for the very first division all operands are single words and thus we can assume we have a relatively fast division operation (and additionally working only with words avoids dynamic allocation).<commit_after>/*
* Montgomery Exponentiation
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/internal/def_powm.h>
#include <botan/numthry.h>
#include <botan/internal/mp_core.h>

namespace Botan {

namespace {

/*
* Compute -input^-1 mod 2^MP_WORD_BITS. We are assured that the
* inverse exists because input is odd (checked by checking that the
* modulus is odd in the Montgomery_Exponentiator constructor, and
* input is the low word of the modulus and thus also odd), and thus
* input and 2^n are relatively prime.
*/
word monty_inverse(word input)
   {
   word b = input;
   word x2 = 1, x1 = 0, y2 = 0, y1 = 1;

   // First iteration, a = n+1
   word q = bigint_divop(1, 0, b);
   word r = (MP_WORD_MAX - q*b) + 1;
   word x = x2 - q*x1;
   word y = y2 - q*y1;

   word a = b;
   b = r;
   x2 = x1;
   x1 = x;
   y2 = y1;
   y1 = y;

   while(b > 0)
      {
      q = a / b;
      r = a - q*b;
      x = x2 - q*x1;
      y = y2 - q*y1;

      a = b;
      b = r;
      x2 = x1;
      x1 = x;
      y2 = y1;
      y1 = y;
      }

   // Now invert in addition space
   y2 = (MP_WORD_MAX - y2) + 1;

   return y2;
   }

}

/*
* Set the exponent
*/
void Montgomery_Exponentiator::set_exponent(const BigInt& exp)
   {
   m_exp = exp;
   m_exp_bits = exp.bits();
   }

/*
* Set the base
*/
void Montgomery_Exponentiator::set_base(const BigInt& base)
   {
   m_window_bits = Power_Mod::window_bits(m_exp.bits(), base.bits(), m_hints);

   m_g.resize((1 << m_window_bits) - 1);

   secure_vector<word> z(2 * (m_mod_words + 1));
   secure_vector<word> workspace(z.size());

   m_g[0] = (base >= m_modulus) ? (base % m_modulus) : base;

   bigint_monty_mul(&z[0], z.size(),
                    m_g[0].data(), m_g[0].size(), m_g[0].sig_words(),
                    m_R2_mod.data(), m_R2_mod.size(), m_R2_mod.sig_words(),
                    m_modulus.data(), m_mod_words, m_mod_prime,
                    &workspace[0]);

   m_g[0].assign(&z[0], m_mod_words + 1);

   const BigInt& x = m_g[0];
   const size_t x_sig = x.sig_words();

   for(size_t i = 1; i != m_g.size(); ++i)
      {
      const BigInt& y = m_g[i-1];
      const size_t y_sig = y.sig_words();

      zeroise(z);
      bigint_monty_mul(&z[0], z.size(),
                       x.data(), x.size(), x_sig,
                       y.data(), y.size(), y_sig,
                       m_modulus.data(), m_mod_words, m_mod_prime,
                       &workspace[0]);

      m_g[i].assign(&z[0], m_mod_words + 1);
      }
   }

/*
* Compute the result
*/
BigInt Montgomery_Exponentiator::execute() const
   {
   const size_t exp_nibbles = (m_exp_bits + m_window_bits - 1) / m_window_bits;

   BigInt x = m_R_mod;
   secure_vector<word> z(2 * (m_mod_words + 1));
   secure_vector<word> workspace(2 * (m_mod_words + 1));

   for(size_t i = exp_nibbles; i > 0; --i)
      {
      for(size_t k = 0; k != m_window_bits; ++k)
         {
         zeroise(z);

         bigint_monty_sqr(&z[0], z.size(),
                          x.data(), x.size(), x.sig_words(),
                          m_modulus.data(), m_mod_words, m_mod_prime,
                          &workspace[0]);

         x.assign(&z[0], m_mod_words + 1);
         }

      if(u32bit nibble = m_exp.get_substring(m_window_bits*(i-1), m_window_bits))
         {
         const BigInt& y = m_g[nibble-1];

         zeroise(z);
         bigint_monty_mul(&z[0], z.size(),
                          x.data(), x.size(), x.sig_words(),
                          y.data(), y.size(), y.sig_words(),
                          m_modulus.data(), m_mod_words, m_mod_prime,
                          &workspace[0]);

         x.assign(&z[0], m_mod_words + 1);
         }
      }

   x.get_reg().resize(2*m_mod_words+1);

   bigint_monty_redc(&x[0], x.size(),
                     m_modulus.data(), m_mod_words, m_mod_prime,
                     &workspace[0]);

   x.get_reg().resize(m_mod_words+1);

   return x;
   }

/*
* Montgomery_Exponentiator Constructor
*/
Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod,
                                                   Power_Mod::Usage_Hints hints) :
   m_modulus(mod),
   m_mod_words(m_modulus.sig_words()),
   m_window_bits(1),
   m_hints(hints)
   {
   // Montgomery reduction only works for positive odd moduli
   if(!m_modulus.is_positive() || m_modulus.is_even())
      throw Invalid_Argument("Montgomery_Exponentiator: invalid modulus");

   m_mod_prime = monty_inverse(mod.word_at(0));

   const BigInt r(BigInt::Power2, m_mod_words * BOTAN_MP_WORD_BITS);
   m_R_mod = r % m_modulus;
   m_R2_mod = (m_R_mod * m_R_mod) % m_modulus;
   }

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: RptPage.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2008-01-29 13:42:53 $
 *
 *  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 _REPORT_RPTUIPAGE_HXX
#define _REPORT_RPTUIPAGE_HXX

#ifndef _SVDPAGE_HXX
#include "svx/svdpage.hxx"
#endif
#ifndef _COM_SUN_STAR_REPORT_XREPORTCOMPONENT_HPP_
#include <com/sun/star/report/XReportComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_REPORT_XSECTION_HPP_
#include <com/sun/star/report/XSection.hpp>
#endif
#include "dllapi.h"

namespace rptui
{
//============================================================================
// OReportPage
//============================================================================

class OReportModel;
//class OReportSection;

class REPORTDESIGN_DLLPUBLIC OReportPage : public SdrPage
{
    OReportModel&   rModel;
    ::com::sun::star::uno::Reference< ::com::sun::star::report::XSection >
                    m_xSection;

    OReportPage(const OReportPage&);

    bool m_bSpecialInsertMode;
    std::vector<SdrObject*> m_aTemporaryObjectList;
    // methode to remove temporary objects, created by 'special mode'
    // (BegDragObj)
    void removeTempObject(SdrObject *_pToRemoveObj);

protected:
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > createUnoPage();
public:
    TYPEINFO();

    OReportPage( OReportModel& rModel
                ,const ::com::sun::star::uno::Reference< ::com::sun::star::report::XSection >& _xSection
                ,FASTBOOL bMasterPage=FALSE );

    virtual ~OReportPage();

    virtual SdrPage* Clone() const;
    using SdrPage::Clone;

    virtual void NbcInsertObject(SdrObject* pObj, ULONG nPos, const SdrInsertReason* pReason);
    virtual SdrObject* RemoveObject(ULONG nObjNum);

    /** returns teh index inside the object list which belongs to the report component.
        @param  _xObject    the report component
    */
    ULONG getIndexOf(const ::com::sun::star::uno::Reference< ::com::sun::star::report::XReportComponent >& _xObject);

    /** removes the SdrObject which belongs to the report component.
        @param  _xObject    the report component
    */
    void removeSdrObject(const ::com::sun::star::uno::Reference< ::com::sun::star::report::XReportComponent >& _xObject);

    void setSpecialMode() {m_bSpecialInsertMode = true;}
    bool getSpecialMode() {return m_bSpecialInsertMode;}
    // all temporary objects will remove and destroy
    void resetSpecialMode();

    /** insert a new SdrObject which belongs to the report component.
        @param  _xObject    the report component
    */
    void insertObject(const ::com::sun::star::uno::Reference< ::com::sun::star::report::XReportComponent >& _xObject);

    //inline OReportSection* getReportSection() { return m_pView; }

    /** sets the view to <NULL/>
    */
    //inline void clearSection() { m_pView = NULL; }

    ::com::sun::star::uno::Reference< ::com::sun::star::report::XSection > getSection() const;
};
}
#endif //_REPORT_RPTUIPAGE_HXX
<commit_msg>INTEGRATION: CWS changefileheader (1.3.26); FILE MERGED 2008/04/01 15:23:32 thb 1.3.26.3: #i85898# Stripping all external header guards 2008/04/01 12:33:01 thb 1.3.26.2: #i85898# Stripping all external header guards 2008/03/31 13:31:47 rt 1.3.26.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: RptPage.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _REPORT_RPTUIPAGE_HXX
#define _REPORT_RPTUIPAGE_HXX

#include "svx/svdpage.hxx"
#include <com/sun/star/report/XReportComponent.hpp>
#include <com/sun/star/report/XSection.hpp>
#include "dllapi.h"

namespace rptui
{
//============================================================================
// OReportPage
//============================================================================

class OReportModel;
//class OReportSection;

class REPORTDESIGN_DLLPUBLIC OReportPage : public SdrPage
{
    OReportModel&   rModel;
    ::com::sun::star::uno::Reference< ::com::sun::star::report::XSection >
                    m_xSection;

    OReportPage(const OReportPage&);

    bool m_bSpecialInsertMode;
    std::vector<SdrObject*> m_aTemporaryObjectList;
    // methode to remove temporary objects, created by 'special mode'
    // (BegDragObj)
    void removeTempObject(SdrObject *_pToRemoveObj);

protected:
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > createUnoPage();
public:
    TYPEINFO();

    OReportPage( OReportModel& rModel
                ,const ::com::sun::star::uno::Reference< ::com::sun::star::report::XSection >& _xSection
                ,FASTBOOL bMasterPage=FALSE );

    virtual ~OReportPage();

    virtual SdrPage* Clone() const;
    using SdrPage::Clone;

    virtual void NbcInsertObject(SdrObject* pObj, ULONG nPos, const SdrInsertReason* pReason);
    virtual SdrObject* RemoveObject(ULONG nObjNum);

    /** returns teh index inside the object list which belongs to the report component.
        @param  _xObject    the report component
    */
    ULONG getIndexOf(const ::com::sun::star::uno::Reference< ::com::sun::star::report::XReportComponent >& _xObject);

    /** removes the SdrObject which belongs to the report component.
        @param  _xObject    the report component
    */
    void removeSdrObject(const ::com::sun::star::uno::Reference< ::com::sun::star::report::XReportComponent >& _xObject);

    void setSpecialMode() {m_bSpecialInsertMode = true;}
    bool getSpecialMode() {return m_bSpecialInsertMode;}
    // all temporary objects will remove and destroy
    void resetSpecialMode();

    /** insert a new SdrObject which belongs to the report component.
        @param  _xObject    the report component
    */
    void insertObject(const ::com::sun::star::uno::Reference< ::com::sun::star::report::XReportComponent >& _xObject);

    //inline OReportSection* getReportSection() { return m_pView; }

    /** sets the view to <NULL/>
    */
    //inline void clearSection() { m_pView = NULL; }

    ::com::sun::star::uno::Reference< ::com::sun::star::report::XSection > getSection() const;
};
}
#endif //_REPORT_RPTUIPAGE_HXX
<|endoftext|>


<commit_before>/*
Resembla: Word-based Japanese similar sentence search library
https://github.com/tuem/resembla

Copyright 2017 Takashi Uemura

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.
*/

#ifndef RESEMBLA_KANA_MISMATCH_COST_HPP
#define RESEMBLA_KANA_MISMATCH_COST_HPP

#include <string>
#include <fstream>
#include <iostream>
#include <unordered_set>
#include <unordered_map>

#include "../string_util.hpp"

namespace resembla {

template<typename string_type>
struct KanaMismatchCost
{
    using value_type = typename string_type::value_type;

    KanaMismatchCost(const std::string& letter_similarity_file_path)
    {
        if(letter_similarity_file_path.empty()){
            return;
        }

        std::basic_ifstream<value_type> ifs(letter_similarity_file_path);
        if(ifs.fail()){
            throw std::runtime_error("input file is not available: " + letter_similarity_file_path);
        }

        while(ifs.good()){
            string_type line;
            std::getline(ifs, line);
            if(ifs.eof() || line.length() == 0){
                break;
            }

            auto columns = split(line, column_delimiter<value_type>());
            if(columns.size() < 2){
                throw std::runtime_error("invalid line in " + letter_similarity_file_path + ": " + cast_string<std::string>(line));
            }
            auto letters= columns[0];
            auto cost = std::stod(columns[1]);

            std::sort(std::begin(letters), std::end(letters));
            for(size_t i = 0; i < letters.size() - 1; ++i){
                string_type s(1, letters[i]);
                for(size_t j = i + 1; j < letters.size(); ++j){
                    string_type p = s + letters[j];
                    letter_similarities[p] = cost;
                }
            }
        }
    }

    double operator()(const value_type a, const value_type b) const
    {
        if(a == b){
            return 0.0;
        }

        auto p = letter_similarities.find(a < b ? string_type({a, b}) : string_type({b, a}));
        if(p != std::end(letter_similarities)){
            return p->second;
        }

        return 1.0;
    }

protected:
    std::unordered_map<string_type, double> letter_similarities;
};

}
#endif
<commit_msg>fix include headers<commit_after>/*
Resembla: Word-based Japanese similar sentence search library
https://github.com/tuem/resembla

Copyright 2017 Takashi Uemura

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.
*/

#ifndef RESEMBLA_KANA_MISMATCH_COST_HPP
#define RESEMBLA_KANA_MISMATCH_COST_HPP

#include <string>
#include <fstream>
#include <iostream>
#include <unordered_map>
#include <algorithm>

#include "../string_util.hpp"

namespace resembla {

template<typename string_type>
struct KanaMismatchCost
{
    using value_type = typename string_type::value_type;

    KanaMismatchCost(const std::string& letter_similarity_file_path)
    {
        if(letter_similarity_file_path.empty()){
            return;
        }

        std::basic_ifstream<value_type> ifs(letter_similarity_file_path);
        if(ifs.fail()){
            throw std::runtime_error("input file is not available: " + letter_similarity_file_path);
        }

        while(ifs.good()){
            string_type line;
            std::getline(ifs, line);
            if(ifs.eof() || line.length() == 0){
                break;
            }

            auto columns = split(line, column_delimiter<value_type>());
            if(columns.size() < 2){
                throw std::runtime_error("invalid line in " + letter_similarity_file_path + ": " + cast_string<std::string>(line));
            }
            auto letters= columns[0];
            auto cost = std::stod(columns[1]);

            std::sort(std::begin(letters), std::end(letters));
            for(size_t i = 0; i < letters.size() - 1; ++i){
                string_type s(1, letters[i]);
                for(size_t j = i + 1; j < letters.size(); ++j){
                    string_type p = s + letters[j];
                    letter_similarities[p] = cost;
                }
            }
        }
    }

    double operator()(const value_type a, const value_type b) const
    {
        if(a == b){
            return 0.0;
        }

        auto p = letter_similarities.find(a < b ? string_type({a, b}) : string_type({b, a}));
        if(p != std::end(letter_similarities)){
            return p->second;
        }

        return 1.0;
    }

protected:
    std::unordered_map<string_type, double> letter_similarities;
};

}
#endif
<|endoftext|>


<commit_before>/*
 * Program.cxx
 *
 * Author
 *     Andrew Brown <adb1413@rit.edu>
 */
#include "config.h"
#include <stdexcept>
#include "glycerin/Program.hxx"
using namespace std;
namespace Glycerin {

/**
 * Constructs a program wrapping an existing shader program.
 *
 * @param handle Existing shader program to wrap
 * @throws invalid_argument if handle is not an existing OpenGL shader program
 */
Program::Program(GLuint handle) : _handle(handle) {
    if (!glIsProgram(_handle)) {
        throw invalid_argument("[Program] Handle not an existing OpenGL shader program!");
    }
}

/**
 * Construcs a program by copying another program.
 *
 * @param program Program to copy
 */
Program::Program(const Program& program) : _handle(program._handle) {
    // pass
}

/**
 * Returns all the active attributes in the program.
 */
map<string,Attribute> Program::activeAttributes() const {

    // Get number of active attributes
    GLint num;
    glGetProgramiv(_handle, GL_ACTIVE_ATTRIBUTES, &num);
    if (num == 0) {
        return map<string,Attribute>();
    }

    // Make a buffer to hold name of an attribute
    GLint len;
    glGetProgramiv(_handle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
    char* const buf = new char[len];

    // Make variables to hold size and type of an attribute
    GLint size;
    GLenum type;

    // Put active attributes into a map
    map<string,Attribute> attribs;
    for (int i = 0; i < num; ++i) {
        glGetActiveAttrib(_handle, i, len, NULL, &size, &type, buf);
        const GLint location = glGetAttribLocation(_handle, buf);
        const string name = buf;
        const Attribute attrib(location, name, _handle, size, type);
        attribs.insert(pair<string,Attribute>(name, attrib));
    }

    // Delete the buffer
    delete[] buf;

    // Return the vector
    return attribs;
}

/**
 * Returns all the active uniforms in the program.
 */
map<string,Uniform> Program::activeUniforms() const {

    // Get number of active uniforms
    GLint num;
    glGetProgramiv(_handle, GL_ACTIVE_UNIFORMS, &num);
    if (num == 0) {
        return map<string,Uniform>();
    }

    // Make a buffer to hold name of a uniform
    GLint len;
    glGetProgramiv(_handle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &len);
    char* const buf = new char[len];

    // Make variables to hold size and type of a uniform
    GLint size;
    GLenum type;

    // Put active uniforms into a map
    map<string,Uniform> uniforms;
    for (int i = 0; i < num; ++i) {
        glGetActiveUniform(_handle, i, len, NULL, &size, &type, buf);
        const GLint location = glGetUniformLocation(_handle, buf);
        const string name = buf;
        const Uniform uniform(location, name, _handle, size, type);
        uniforms.insert(pair<string,Uniform>(name, uniform));
    }

    // Delete the buffer
    delete[] buf;

    // Return the vector
    return uniforms;
}

/**
 * Attaches a shader to the program.
 *
 * @param shader OpenGL identifier for the shader to attach
 * @throw std::invalid_argument if shader is not valid
 * @throw std::invalid_argument if shader is already attached
 */
void Program::attachShader(GLuint shader) {
    attachShader(Shader::wrap(shader));
}

/**
 * Attaches a shader to the program.
 *
 * @param shader Wrapper for an OpenGL shader
 * @throw std::invalid_argument if shader is already attached
 */
void Program::attachShader(const Shader &shader) {
    if (isAttached(shader)) {
        throw invalid_argument("[Program] Shader is already attached!");
    }
    glAttachShader(_handle, shader.handle());
}

/**
 * Determines the location of an attribute.
 *
 * @param name Name of attribute
 * @throws invalid_argument if name empty
 * @throws runtime_error if program has not been linked yet
 */
GLint Program::attribLocation(const std::string &name) const {

    if (name.empty()) {
        throw invalid_argument("[Program] Name is empty!");
    } else if (!linked()) {
        throw runtime_error("[Program] Program not linked yet!");
    }

    return glGetAttribLocation(_handle, name.c_str());
}

/**
 * Binds an attribute to a specific location.
 *
 * @param name Name of attribute
 * @param location Location to bind to
 * @throw invalid_argument if name is empty
 */
void Program::attribLocation(const std::string& name, GLuint location) {
    if (name.empty()) {
        throw invalid_argument("[Program] Name is empty!");
    }
    glBindAttribLocation(_handle, location, name.c_str());
}

/**
 * Creates a new program.
 *
 * @return New program instance
 * @throws std::runtime_error if program could not be created
 */
Program Program::create() {

    // Create a handle
    const GLuint handle = glCreateProgram();
    if (handle == 0) {
        throw runtime_error("[Program] Could not create program!");
    }

    // Make the program
    return Program(handle);
}

/**
 * Detaches a shader from the program.
 *
 * @param shader Shader to detach
 * @throws invalid_argument if shader is not a valid shader
 * @throws invalid_argument if shader is not already attached
 */
void Program::detachShader(GLuint shader) {
    detachShader(Shader::wrap(shader));
}

/**
 * Detaches a shader from the program.
 *
 * @param shader Shader to detach
 * @throws invalid_argument if shader is not already attached
 */
void Program::detachShader(const Shader &shader) {
    if (!isAttached(shader)) {
        throw invalid_argument("[Program] Shader not already attached!");
    }
    glDetachShader(_handle, shader.handle());
}

/**
 * Deletes the underlying OpenGL shader program.
 */
void Program::dispose() {
    glDeleteProgram(_handle);
}

/**
 * Returns the location of an output variable.
 *
 * @param name Name of output variable
 * @return Location of output variable, or -1 if name is not an active output variable
 */
GLint Program::fragDataLocation(const std::string& name) const {
    return glGetFragDataLocation(_handle, name.c_str());
}

/**
 * Binds a fragment shader output variable to a location.
 *
 * @param name Name of output variable to bind
 * @param location Location of draw buffer to bind to
 * @throws invalid_argument if location greater than GL_MAX_DRAW_BUFFERS
 * @throws invalid_argument if name is empty or starts with 'gl_'
 */
void Program::fragDataLocation(const std::string &name, GLuint location) {

    if (location > getMaxDrawBuffers()) {
        throw invalid_argument("[Program] Location greater than GL_MAX_DRAW_BUFFERS");
    } else if (name.empty()) {
        throw invalid_argument("[Program] Name is empty!");
    } else if (name.find("gl_") == 0) {
        throw invalid_argument("[Program] Name starts with 'gl_'");
    }

    glBindFragDataLocation(_handle, location, name.c_str());
}

/**
 * Returns the OpenGL indentifier for the program.
 */
GLuint Program::handle() const {
    return _handle;
}

/**
 * Links the program.
 */
void Program::link() {
    glLinkProgram(_handle);
}

/**
 * Returns `true` if program is linked.
 */
bool Program::linked() const {
    GLint linked;
    glGetProgramiv(_handle, GL_LINK_STATUS, &linked);
    return linked;
}

/**
 * Returns the program's log.
 */
string Program::log() const {

    // Make a buffer big enough to hold the log
    GLint len;
    glGetProgramiv(_handle, GL_INFO_LOG_LENGTH, &len);
    GLchar* const buf = new GLchar[len + 1];

    // Put the log into the buffer
    GLint num;
    glGetProgramInfoLog(_handle, len, &num, buf);
    buf[num] = '\0';

    // Make a string from the buffer and then delete it
    string str(buf);
    delete[] buf;

    // Return the string
    return str;
}

/**
 * Copies the handle of another program.
 *
 * @param program Program to copy
 * @return Reference to this program
 */
Program& Program::operator=(const Program& program) {
    _handle = program.handle();
}

/**
 * Checks if another program has the same handle as this one.
 *
 * @param program Program to check
 * @return `true` if both programs have same handle
 */
bool Program::operator==(const Program& program) const {
    return _handle == program.handle();
}

/**
 * Checks if another program has a different handle than this one.
 *
 * @param program Program to check
 * @return `true` if programs have different handles
 */
bool Program::operator!=(const Program& program) const {
    return _handle != program.handle();
}

/**
 * Returns all the shaders attached to the program.
 */
vector<Shader> Program::shaders() const {

    // Determine how many shaders are attached
    GLint len;
    glGetProgramiv(_handle, GL_ATTACHED_SHADERS, &len);
    if (len == 0) {
        return vector<Shader>();
    }

    // Put attached shaders into array
    GLuint* const arr = new GLuint[len];
    glGetAttachedShaders(_handle, len, NULL, arr);

    // Add them to a vector
    vector<Shader> vec;
    for (int i = 0; i < len; ++i) {
        Shader shader = Shader::wrap(arr[i]);
        vec.push_back(shader);
    }

    // Delete the array
    delete[] arr;

    // Return the vector
    return vec;
}

/**
 * Determines the location of a uniform in the program.
 *
 * @param name Name of the uniform to look for
 * @return Location of the uniform, or `-1` if not in program
 */
GLint Program::uniformLocation(const string& name) const {
    return glGetUniformLocation(_handle, name.c_str());
}

/**
 * Activates the program.
 */
void Program::use() const {
    glUseProgram(_handle);
}

/**
 * Checks if the program is valid.
 */
bool Program::valid() const {
    GLint valid;
    glGetProgramiv(_handle, GL_VALIDATE_STATUS, &valid);
    return valid;
}

/**
 * Ensures the program is valid.
 */
void Program::validate() {
    glValidateProgram(_handle);
}

/**
 * Wraps an existing OpenGL program.
 *
 * @param handle OpenGL identifier for program
 * @return Wrapper for OpenGL program
 * @throws std::invalid_argument if handle is not an OpenGL program
 */
Program Program::wrap(const GLuint handle) {
    return Program(handle);
}

// HELPERS

/**
 * Checks if a shader is attached to the program.
 *
 * @param shader Shader to check
 * @return `true` if shader is attached
 */
bool Program::isAttached(const Shader &shader) const {
    const vector<Shader> attachedShaders = shaders();
    vector<Shader>::const_iterator it = attachedShaders.begin();
    while (it != attachedShaders.end()) {
        if ((*it) == shader) {
            return true;
        }
        ++it;
    }
    return false;
}

/**
 * Returns the value of GL_MAX_DRAW_BUFFERS.
 */
GLint Program::getMaxDrawBuffers() {
    GLint value;
    glGetIntegerv(GL_MAX_DRAW_BUFFERS, &value);
    return value;
}

} /* namespace Glycerin */
<commit_msg>Fixed a typo in Program copy ctor doxygen (ref #32)<commit_after>/*
 * Program.cxx
 *
 * Author
 *     Andrew Brown <adb1413@rit.edu>
 */
#include "config.h"
#include <stdexcept>
#include "glycerin/Program.hxx"
using namespace std;
namespace Glycerin {

/**
 * Constructs a program wrapping an existing shader program.
 *
 * @param handle Existing shader program to wrap
 * @throws invalid_argument if handle is not an existing OpenGL shader program
 */
Program::Program(GLuint handle) : _handle(handle) {
    if (!glIsProgram(_handle)) {
        throw invalid_argument("[Program] Handle not an existing OpenGL shader program!");
    }
}

/**
 * Constructs a program by copying another program.
 *
 * @param program Program to copy
 */
Program::Program(const Program& program) : _handle(program._handle) {
    // pass
}

/**
 * Returns all the active attributes in the program.
 */
map<string,Attribute> Program::activeAttributes() const {

    // Get number of active attributes
    GLint num;
    glGetProgramiv(_handle, GL_ACTIVE_ATTRIBUTES, &num);
    if (num == 0) {
        return map<string,Attribute>();
    }

    // Make a buffer to hold name of an attribute
    GLint len;
    glGetProgramiv(_handle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
    char* const buf = new char[len];

    // Make variables to hold size and type of an attribute
    GLint size;
    GLenum type;

    // Put active attributes into a map
    map<string,Attribute> attribs;
    for (int i = 0; i < num; ++i) {
        glGetActiveAttrib(_handle, i, len, NULL, &size, &type, buf);
        const GLint location = glGetAttribLocation(_handle, buf);
        const string name = buf;
        const Attribute attrib(location, name, _handle, size, type);
        attribs.insert(pair<string,Attribute>(name, attrib));
    }

    // Delete the buffer
    delete[] buf;

    // Return the vector
    return attribs;
}

/**
 * Returns all the active uniforms in the program.
 */
map<string,Uniform> Program::activeUniforms() const {

    // Get number of active uniforms
    GLint num;
    glGetProgramiv(_handle, GL_ACTIVE_UNIFORMS, &num);
    if (num == 0) {
        return map<string,Uniform>();
    }

    // Make a buffer to hold name of a uniform
    GLint len;
    glGetProgramiv(_handle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &len);
    char* const buf = new char[len];

    // Make variables to hold size and type of a uniform
    GLint size;
    GLenum type;

    // Put active uniforms into a map
    map<string,Uniform> uniforms;
    for (int i = 0; i < num; ++i) {
        glGetActiveUniform(_handle, i, len, NULL, &size, &type, buf);
        const GLint location = glGetUniformLocation(_handle, buf);
        const string name = buf;
        const Uniform uniform(location, name, _handle, size, type);
        uniforms.insert(pair<string,Uniform>(name, uniform));
    }

    // Delete the buffer
    delete[] buf;

    // Return the vector
    return uniforms;
}

/**
 * Attaches a shader to the program.
 *
 * @param shader OpenGL identifier for the shader to attach
 * @throw std::invalid_argument if shader is not valid
 * @throw std::invalid_argument if shader is already attached
 */
void Program::attachShader(GLuint shader) {
    attachShader(Shader::wrap(shader));
}

/**
 * Attaches a shader to the program.
 *
 * @param shader Wrapper for an OpenGL shader
 * @throw std::invalid_argument if shader is already attached
 */
void Program::attachShader(const Shader &shader) {
    if (isAttached(shader)) {
        throw invalid_argument("[Program] Shader is already attached!");
    }
    glAttachShader(_handle, shader.handle());
}

/**
 * Determines the location of an attribute.
 *
 * @param name Name of attribute
 * @throws invalid_argument if name empty
 * @throws runtime_error if program has not been linked yet
 */
GLint Program::attribLocation(const std::string &name) const {

    if (name.empty()) {
        throw invalid_argument("[Program] Name is empty!");
    } else if (!linked()) {
        throw runtime_error("[Program] Program not linked yet!");
    }

    return glGetAttribLocation(_handle, name.c_str());
}

/**
 * Binds an attribute to a specific location.
 *
 * @param name Name of attribute
 * @param location Location to bind to
 * @throw invalid_argument if name is empty
 */
void Program::attribLocation(const std::string& name, GLuint location) {
    if (name.empty()) {
        throw invalid_argument("[Program] Name is empty!");
    }
    glBindAttribLocation(_handle, location, name.c_str());
}

/**
 * Creates a new program.
 *
 * @return New program instance
 * @throws std::runtime_error if program could not be created
 */
Program Program::create() {

    // Create a handle
    const GLuint handle = glCreateProgram();
    if (handle == 0) {
        throw runtime_error("[Program] Could not create program!");
    }

    // Make the program
    return Program(handle);
}

/**
 * Detaches a shader from the program.
 *
 * @param shader Shader to detach
 * @throws invalid_argument if shader is not a valid shader
 * @throws invalid_argument if shader is not already attached
 */
void Program::detachShader(GLuint shader) {
    detachShader(Shader::wrap(shader));
}

/**
 * Detaches a shader from the program.
 *
 * @param shader Shader to detach
 * @throws invalid_argument if shader is not already attached
 */
void Program::detachShader(const Shader &shader) {
    if (!isAttached(shader)) {
        throw invalid_argument("[Program] Shader not already attached!");
    }
    glDetachShader(_handle, shader.handle());
}

/**
 * Deletes the underlying OpenGL shader program.
 */
void Program::dispose() {
    glDeleteProgram(_handle);
}

/**
 * Returns the location of an output variable.
 *
 * @param name Name of output variable
 * @return Location of output variable, or -1 if name is not an active output variable
 */
GLint Program::fragDataLocation(const std::string& name) const {
    return glGetFragDataLocation(_handle, name.c_str());
}

/**
 * Binds a fragment shader output variable to a location.
 *
 * @param name Name of output variable to bind
 * @param location Location of draw buffer to bind to
 * @throws invalid_argument if location greater than GL_MAX_DRAW_BUFFERS
 * @throws invalid_argument if name is empty or starts with 'gl_'
 */
void Program::fragDataLocation(const std::string &name, GLuint location) {

    if (location > getMaxDrawBuffers()) {
        throw invalid_argument("[Program] Location greater than GL_MAX_DRAW_BUFFERS");
    } else if (name.empty()) {
        throw invalid_argument("[Program] Name is empty!");
    } else if (name.find("gl_") == 0) {
        throw invalid_argument("[Program] Name starts with 'gl_'");
    }

    glBindFragDataLocation(_handle, location, name.c_str());
}

/**
 * Returns the OpenGL indentifier for the program.
 */
GLuint Program::handle() const {
    return _handle;
}

/**
 * Links the program.
 */
void Program::link() {
    glLinkProgram(_handle);
}

/**
 * Returns `true` if program is linked.
 */
bool Program::linked() const {
    GLint linked;
    glGetProgramiv(_handle, GL_LINK_STATUS, &linked);
    return linked;
}

/**
 * Returns the program's log.
 */
string Program::log() const {

    // Make a buffer big enough to hold the log
    GLint len;
    glGetProgramiv(_handle, GL_INFO_LOG_LENGTH, &len);
    GLchar* const buf = new GLchar[len + 1];

    // Put the log into the buffer
    GLint num;
    glGetProgramInfoLog(_handle, len, &num, buf);
    buf[num] = '\0';

    // Make a string from the buffer and then delete it
    string str(buf);
    delete[] buf;

    // Return the string
    return str;
}

/**
 * Copies the handle of another program.
 *
 * @param program Program to copy
 * @return Reference to this program
 */
Program& Program::operator=(const Program& program) {
    _handle = program.handle();
}

/**
 * Checks if another program has the same handle as this one.
 *
 * @param program Program to check
 * @return `true` if both programs have same handle
 */
bool Program::operator==(const Program& program) const {
    return _handle == program.handle();
}

/**
 * Checks if another program has a different handle than this one.
 *
 * @param program Program to check
 * @return `true` if programs have different handles
 */
bool Program::operator!=(const Program& program) const {
    return _handle != program.handle();
}

/**
 * Returns all the shaders attached to the program.
 */
vector<Shader> Program::shaders() const {

    // Determine how many shaders are attached
    GLint len;
    glGetProgramiv(_handle, GL_ATTACHED_SHADERS, &len);
    if (len == 0) {
        return vector<Shader>();
    }

    // Put attached shaders into array
    GLuint* const arr = new GLuint[len];
    glGetAttachedShaders(_handle, len, NULL, arr);

    // Add them to a vector
    vector<Shader> vec;
    for (int i = 0; i < len; ++i) {
        Shader shader = Shader::wrap(arr[i]);
        vec.push_back(shader);
    }

    // Delete the array
    delete[] arr;

    // Return the vector
    return vec;
}

/**
 * Determines the location of a uniform in the program.
 *
 * @param name Name of the uniform to look for
 * @return Location of the uniform, or `-1` if not in program
 */
GLint Program::uniformLocation(const string& name) const {
    return glGetUniformLocation(_handle, name.c_str());
}

/**
 * Activates the program.
 */
void Program::use() const {
    glUseProgram(_handle);
}

/**
 * Checks if the program is valid.
 */
bool Program::valid() const {
    GLint valid;
    glGetProgramiv(_handle, GL_VALIDATE_STATUS, &valid);
    return valid;
}

/**
 * Ensures the program is valid.
 */
void Program::validate() {
    glValidateProgram(_handle);
}

/**
 * Wraps an existing OpenGL program.
 *
 * @param handle OpenGL identifier for program
 * @return Wrapper for OpenGL program
 * @throws std::invalid_argument if handle is not an OpenGL program
 */
Program Program::wrap(const GLuint handle) {
    return Program(handle);
}

// HELPERS

/**
 * Checks if a shader is attached to the program.
 *
 * @param shader Shader to check
 * @return `true` if shader is attached
 */
bool Program::isAttached(const Shader &shader) const {
    const vector<Shader> attachedShaders = shaders();
    vector<Shader>::const_iterator it = attachedShaders.begin();
    while (it != attachedShaders.end()) {
        if ((*it) == shader) {
            return true;
        }
        ++it;
    }
    return false;
}

/**
 * Returns the value of GL_MAX_DRAW_BUFFERS.
 */
GLint Program::getMaxDrawBuffers() {
    GLint value;
    glGetIntegerv(GL_MAX_DRAW_BUFFERS, &value);
    return value;
}

} /* namespace Glycerin */
<|endoftext|>