<commit_before>/**
 * @file    Heap.cpp
 * @author  niob
 * @date    Oct 21, 2016
 * @brief   Defines the {@link Heap} and {@link HeapBase} classes.
 */

#include "Heap.hpp"

#include <algorithm>
#include <cassert>
#include <iomanip>
#include <iterator>
#include <utility>
#include <type_traits>

#include "RestoreStream.hpp"
#include "TaggedPointer.hpp"

namespace ssw {

/**
 * Represents a block of memory in the heap. This class holds the block size and either a pointer to the
 * type of the stored object (in case the block is used) or a pointer to the next free block.
 */
class alignas(HeapBase::Align) HeapBase::Block
{
	std::size_t mSize;
	TaggedPointer mPtr;

public:

	/**
	 * Initialize a new, free block with the specified size.
	 *
	 * @param size The usable size of the block (will be properly aligned).
	 * @param next (optional) The next block in the free list.
	 */
	explicit Block(std::size_t size, Block *next = nullptr) noexcept
			: mSize(size), mPtr(next) {
		assert(size >= Align);
		mPtr.free(true);
	}

	/**
	 * Get the data size of this block.
	 *
	 * @return The usable size of this block, not including the block descriptor.
	 */
	std::size_t size() const noexcept {
		return mSize;
	}

	/**
	 * Mark this block as free and set the next block in the free list.
	 *
	 * @param next The next block in the free list, or `nullptr`.
	 */
	void next(Block *next) noexcept {
		assert(next != this);
		mPtr = next;
		mPtr.free(true);
	}

	/**
	 * Mark this block as free and set its successor and size.
	 *
	 * @param next The next block in the free list, or `nullptr`.
	 * @param size The usable size of this block, not including the block descriptor.
	 */
	void next(Block *next, std::size_t size) noexcept {
		this->next(next);
		assert(size >= Align);
		mSize = size;
	}

	/**
	 * Get the next block in the free list. This block must represent a free block.
	 *
	 * @return Pointer to the next block in the free list.
	 */
	Block* next() const noexcept {
		assert(this->free() && !this->mark());
		return mPtr.get<Block>();
	}

	/**
	 * Get a pointer to the block following this block in the heap.
	 *
	 * @return Pointer to the physically next block in the heap.
	 */
	Block* following() const noexcept {
		return reinterpret_cast<Block*>(this->data() + align(mSize));
	}

	/**
	 * Mark this block as used and set the data type.
	 *
	 * @param type The type descriptor for the data in this block.
	 */
	void type(const TypeDescriptor &type) noexcept {
		mPtr = &type;
		mPtr.free(false);
	}

	/**
	 * Get the data type in this block. This block must represent a used block.
	 *
	 * @return Reference to the type descriptor for the data in this block.
	 */
	const TypeDescriptor& type() const noexcept {
		assert(this->used() && !this->mark());
		return *mPtr.get<const TypeDescriptor>();
	}

	/**
	 * Get whether this block is free.
	 *
	 * @return `true` if this block is part of the free list and does not hold an object.
	 */
	bool free() const noexcept {
		return mPtr.free();
	}

	/**
	 * Get whether this block is used.
	 *
	 * @return `true` if this block contains an object and is not part of the free list.
	 */
	bool used() const noexcept {
		return mPtr.used();
	}

	/**
	 * Get the GC mark for this block.
	 *
	 * @return `true` if the mark is set, `false` otherwise.
	 */
	bool mark() const noexcept {
		return mPtr.mark();
	}

	/**
	 * Get the pointer in this block.
	 *
	 * @return Reference to the pointer.
	 */
	TaggedPointer& ptr() noexcept {
		return mPtr;
	}

	/**
	 * Get a pointer to the data portion of this block.
	 *
	 * @return Pointer to the data portion of this block.
	 */
	byte* data() const noexcept {
		return const_cast<byte*>(reinterpret_cast<const byte*>(this) + Align);
	}

	/**
	 * Split this block in two blocks if possible. If there is enough space for another block, then this
	 * block will be resized to the new size and a new block will be added after it; if there is not enough
	 * space then nothing will be changed. This block must be a free block.
	 *
	 * @param newSize The new size of this block, will be properly aligned.
	 */
	void split(std::size_t newSize) noexcept {
		assert(this->free());
		const std::size_t restSize = align(mSize) - align(newSize) - Align;
		if(restSize >= Align) {
			Block *newBlock = reinterpret_cast<Block*>(reinterpret_cast<byte*>(this) + Align + align(newSize));
			new(newBlock) Block(restSize, mPtr.get<Block>());
			mPtr = newBlock;
		}
	}
};

HeapBase::HeapBase(byte *storage, std::size_t size) noexcept
		: mFreeList(reinterpret_cast<Block*>(storage)),
		  mHeapStart(reinterpret_cast<Block*>(storage)),
		  mHeapEnd(reinterpret_cast<Block*>(storage + (size & ~(Align - 1)))),
		  mRoots() {
	static_assert(sizeof(Block) <= Align, "Block class is too large");

	assert((reinterpret_cast<std::uintptr_t>(storage) & (Align - 1)) == 0);
	assert(size >= 2 * Align);

	new(mFreeList) Block(size - Align);
}

void* HeapBase::allocate(const TypeDescriptor &type, bool isRoot) noexcept {
	if(mFreeList == nullptr) {
		// There are no free blocks at all, don't even try
		return nullptr;
	}

	auto result = this->tryAllocate(type);
	if(!result) {
		// No sufficiently sized block found using first-fit, merge blocks and try again
		this->mergeBlocks();
		result = this->tryAllocate(type);
	}
	if(result && isRoot) {
		this->registerRoot(result);
	}
	return result;
}

void* HeapBase::tryAllocate(const TypeDescriptor &type) noexcept {
	Block *prev = nullptr;
	Block *cur = mFreeList;
	// Use first-fit method to find a block
	while(cur && cur->size() < type.size()) {
		prev = std::exchange(cur, cur->next());
	}
	if(cur) {
		cur->split(type.size());
		if(prev) {
			prev->next(cur->next());
		} else {
			mFreeList = cur->next();
		}
		cur->type(type);
		return cur->data();
	}
	return nullptr;
}

void HeapBase::mergeBlocks() noexcept {
	// TODO implement merging of free blocks
}

void HeapBase::deallocate(byte *obj) noexcept {
	Block &blk = block(obj);
	assert(blk.used() /* Tried to deallocate an unused block */);
	assert(!blk.mark() /* Tried to deallocate during garbage collection (GC builds a new free list itself) */);

	blk.next(mFreeList);
	mFreeList = &blk;
}

void HeapBase::gc() noexcept {
	for(auto root : mRoots) {
		this->mark(root);
	}
	this->rebuildFreeList();
}

// Mark the object graph for the specified heap root object using the Deutsch-Schorr-Waite marking algorithm
void HeapBase::mark(byte *root) noexcept {
	assert(root);
	assert(!block(root).mark());

	byte *cur = root;
	byte *prev = nullptr;
	while(true) {
		auto &blk = block(cur);
		if(!blk.mark()) {
			// Mark the object and begin iteration
			blk.ptr() = blk.type().begin();
			blk.ptr().mark(true);
		} else {
			blk.ptr() = blk.ptr().get<const std::ptrdiff_t>() + 1;
		}

		auto offset = *blk.ptr().get<const std::ptrdiff_t>();
		if(offset >= 0) {
			// Advance
			auto &field = *reinterpret_cast<byte**>(cur + offset);
			if(field && !block(field).mark()) {
				auto tmp = std::exchange(field, prev);
				prev = std::exchange(cur, tmp);
			}
		} else {
			// Retreat
			blk.ptr() = reinterpret_cast<const TypeDescriptor*>(
					reinterpret_cast<const byte*>(blk.ptr().get<const std::ptrdiff_t>()) + offset);
			if(!prev) {
				return;
			}
			auto tmp = std::exchange(cur, prev);
			offset = *block(cur).ptr().get<std::ptrdiff_t>();
			prev = std::exchange(*reinterpret_cast<byte**>(cur + offset), tmp);
		}
	} // while(true)
}

// Rebuild the free list while destroying garbage objects
void HeapBase::rebuildFreeList() noexcept {
	Block *freeList = nullptr;

	for(Block *blk = mHeapStart; blk < mHeapEnd;) {
		if(blk->mark()) {
			blk->ptr().mark(false);
			blk = blk->following();

		} else {
			auto free = blk;
			// Extend the free block, destroying garbage objects as necessary
			do {
				if(free->used()) {
					free->type().destroy(free->data());
				}
				free = free->following();
			} while(free < mHeapEnd && !free->mark());

			static_assert(std::is_trivially_destructible<Block>::value, "Block must be trivially destructible.");
			blk->next(freeList, reinterpret_cast<byte*>(free) - reinterpret_cast<byte*>(blk) - Align);
			freeList = blk;
			blk = free;
		}
	}
	mFreeList = freeList;
}

void HeapBase::dump(std::ostream &os) {
	RestoreStream osRestore{os};

	const HeapStats stats = this->collectHeapStats(true);

	os << "==== Statistics for heap at 0x" << std::hex << mHeapStart << std::dec << " ====\n";
	os << "Heap size:  " << stats.heapSize << " bytes\n";
	os << "Used space: " << stats.usedSize << " bytes\n";
	os << "Free space: " << stats.freeSize << " bytes\n";
	os << '\n';
	os << "Object count:    " << stats.numObjects << " (" << stats.numLiveObjects << " live)\n";
	os << "Object size:     " << stats.objectSize << " bytes (" << stats.liveObjectSize << " in live objects)\n";
	os << "Available space: " << stats.freeBlockSize << "bytes in " << stats.numFreeBlocks << " blocks\n";
	os << '\n';
	os << "= Free Blocks =\nAddress    Size(net)\n";

	// Print free blocks: just use the free list
	os.fill('0');
	for(auto blk = mFreeList; blk; blk = blk->next()) {
		os << std::hex << "0x" << std::setw(sizeof(void*)) << blk
				<< ' ' << std::dec << blk->size() << '\n';
	}
	os << std::setfill(' ') << '\n';

	os << "= Live Objects =\n";
	// For printing live objects we need to do marking
	this->dumpLiveObjects(os);
}

void HeapBase::dumpLiveObjects(std::ostream &os) {
	constexpr std::size_t numDataBytes = 4;
	static const std::string indent(4, ' ');

	for(auto root : mRoots) {
		this->mark(root);
	}
	os << std::hex;
	for(auto blk = mHeapStart; blk < mHeapEnd; blk = blk->following()) {
		if(blk->mark()) {
			blk->ptr().mark(false);
			os << blk->data() << ' ' << "TODO NAME" << '\n';
			os << "  Data: ";
			std::copy_n(blk->data(), std::min(blk->type().size(), numDataBytes), std::ostream_iterator<int>(os, " "));
			if(blk->type().size() > numDataBytes) {
				os << "...";
			}
			os << "\n  Pointers: ";
			if(blk->type().offsets() > 0) {
				os << "\n";
				for(auto offset : blk->type()) {
					os << indent << *reinterpret_cast<void**>(blk->data() + offset) << '\n';
				}
			} else {
				os << "none\n";
			}
		} // if(blk->mark())
	}
	os << std::dec;
}

HeapBase::HeapStats HeapBase::collectHeapStats(bool countLiveObjects) noexcept {
	HeapStats result{};
	result.heapSize = reinterpret_cast<byte*>(mHeapEnd) - reinterpret_cast<byte*>(mHeapStart);

	if(countLiveObjects) {
		for(auto root : mRoots) {
			this->mark(root);
		}
	}
	for(auto blk = mHeapStart; blk < mHeapEnd; blk = blk->following()) {
		if(blk->free()) {
			result.numFreeBlocks++;
			result.freeBlockSize += blk->size();
			result.freeSize += Align + align(blk->size());
		} else {
			if(blk->mark()) {
				blk->ptr().mark(false);
				result.numLiveObjects++;
				result.liveObjectSize += blk->type().size();
			}
			result.numObjects++;
			result.objectSize += blk->type().size();
			result.usedSize += Align + align(blk->size());
		}
	}
	assert(result.freeSize + result.usedSize == result.heapSize);

	return result;
}

} // namespace ssw
<commit_msg>Fix errors in dump output.<commit_after>/**
 * @file    Heap.cpp
 * @author  niob
 * @date    Oct 21, 2016
 * @brief   Defines the {@link Heap} and {@link HeapBase} classes.
 */

#include "Heap.hpp"

#include <algorithm>
#include <cassert>
#include <iomanip>
#include <iterator>
#include <utility>
#include <type_traits>

#include "RestoreStream.hpp"
#include "TaggedPointer.hpp"

namespace ssw {

/**
 * Represents a block of memory in the heap. This class holds the block size and either a pointer to the
 * type of the stored object (in case the block is used) or a pointer to the next free block.
 */
class alignas(HeapBase::Align) HeapBase::Block
{
	std::size_t mSize;
	TaggedPointer mPtr;

public:

	/**
	 * Initialize a new, free block with the specified size.
	 *
	 * @param size The usable size of the block (will be properly aligned).
	 * @param next (optional) The next block in the free list.
	 */
	explicit Block(std::size_t size, Block *next = nullptr) noexcept
			: mSize(size), mPtr(next) {
		assert(size >= Align);
		mPtr.free(true);
	}

	/**
	 * Get the data size of this block.
	 *
	 * @return The usable size of this block, not including the block descriptor.
	 */
	std::size_t size() const noexcept {
		return mSize;
	}

	/**
	 * Mark this block as free and set the next block in the free list.
	 *
	 * @param next The next block in the free list, or `nullptr`.
	 */
	void next(Block *next) noexcept {
		assert(next != this);
		mPtr = next;
		mPtr.free(true);
	}

	/**
	 * Mark this block as free and set its successor and size.
	 *
	 * @param next The next block in the free list, or `nullptr`.
	 * @param size The usable size of this block, not including the block descriptor.
	 */
	void next(Block *next, std::size_t size) noexcept {
		this->next(next);
		assert(size >= Align);
		mSize = size;
	}

	/**
	 * Get the next block in the free list. This block must represent a free block.
	 *
	 * @return Pointer to the next block in the free list.
	 */
	Block* next() const noexcept {
		assert(this->free() && !this->mark());
		return mPtr.get<Block>();
	}

	/**
	 * Get a pointer to the block following this block in the heap.
	 *
	 * @return Pointer to the physically next block in the heap.
	 */
	Block* following() const noexcept {
		return reinterpret_cast<Block*>(this->data() + align(mSize));
	}

	/**
	 * Mark this block as used and set the data type.
	 *
	 * @param type The type descriptor for the data in this block.
	 */
	void type(const TypeDescriptor &type) noexcept {
		mPtr = &type;
		mPtr.free(false);
	}

	/**
	 * Get the data type in this block. This block must represent a used block.
	 *
	 * @return Reference to the type descriptor for the data in this block.
	 */
	const TypeDescriptor& type() const noexcept {
		assert(this->used() && !this->mark());
		return *mPtr.get<const TypeDescriptor>();
	}

	/**
	 * Get whether this block is free.
	 *
	 * @return `true` if this block is part of the free list and does not hold an object.
	 */
	bool free() const noexcept {
		return mPtr.free();
	}

	/**
	 * Get whether this block is used.
	 *
	 * @return `true` if this block contains an object and is not part of the free list.
	 */
	bool used() const noexcept {
		return mPtr.used();
	}

	/**
	 * Get the GC mark for this block.
	 *
	 * @return `true` if the mark is set, `false` otherwise.
	 */
	bool mark() const noexcept {
		return mPtr.mark();
	}

	/**
	 * Get the pointer in this block.
	 *
	 * @return Reference to the pointer.
	 */
	TaggedPointer& ptr() noexcept {
		return mPtr;
	}

	/**
	 * Get a pointer to the data portion of this block.
	 *
	 * @return Pointer to the data portion of this block.
	 */
	byte* data() const noexcept {
		return const_cast<byte*>(reinterpret_cast<const byte*>(this) + Align);
	}

	/**
	 * Split this block in two blocks if possible. If there is enough space for another block, then this
	 * block will be resized to the new size and a new block will be added after it; if there is not enough
	 * space then nothing will be changed. This block must be a free block.
	 *
	 * @param newSize The new size of this block, will be properly aligned.
	 */
	void split(std::size_t newSize) noexcept {
		assert(this->free());
		const std::size_t restSize = align(mSize) - align(newSize) - Align;
		if(restSize >= Align) {
			Block *newBlock = reinterpret_cast<Block*>(reinterpret_cast<byte*>(this) + Align + align(newSize));
			new(newBlock) Block(restSize, mPtr.get<Block>());
			mPtr = newBlock;
		}
	}
};

HeapBase::HeapBase(byte *storage, std::size_t size) noexcept
		: mFreeList(reinterpret_cast<Block*>(storage)),
		  mHeapStart(reinterpret_cast<Block*>(storage)),
		  mHeapEnd(reinterpret_cast<Block*>(storage + (size & ~(Align - 1)))),
		  mRoots() {
	static_assert(sizeof(Block) <= Align, "Block class is too large");

	assert((reinterpret_cast<std::uintptr_t>(storage) & (Align - 1)) == 0);
	assert(size >= 2 * Align);

	new(mFreeList) Block(size - Align);
}

void* HeapBase::allocate(const TypeDescriptor &type, bool isRoot) noexcept {
	if(mFreeList == nullptr) {
		// There are no free blocks at all, don't even try
		return nullptr;
	}

	auto result = this->tryAllocate(type);
	if(!result) {
		// No sufficiently sized block found using first-fit, merge blocks and try again
		this->mergeBlocks();
		result = this->tryAllocate(type);
	}
	if(result && isRoot) {
		this->registerRoot(result);
	}
	return result;
}

void* HeapBase::tryAllocate(const TypeDescriptor &type) noexcept {
	Block *prev = nullptr;
	Block *cur = mFreeList;
	// Use first-fit method to find a block
	while(cur && cur->size() < type.size()) {
		prev = std::exchange(cur, cur->next());
	}
	if(cur) {
		cur->split(type.size());
		if(prev) {
			prev->next(cur->next());
		} else {
			mFreeList = cur->next();
		}
		cur->type(type);
		return cur->data();
	}
	return nullptr;
}

void HeapBase::mergeBlocks() noexcept {
	// TODO implement merging of free blocks
}

void HeapBase::deallocate(byte *obj) noexcept {
	Block &blk = block(obj);
	assert(blk.used() /* Tried to deallocate an unused block */);
	assert(!blk.mark() /* Tried to deallocate during garbage collection (GC builds a new free list itself) */);

	blk.next(mFreeList);
	mFreeList = &blk;
}

void HeapBase::gc() noexcept {
	for(auto root : mRoots) {
		this->mark(root);
	}
	this->rebuildFreeList();
}

// Mark the object graph for the specified heap root object using the Deutsch-Schorr-Waite marking algorithm
void HeapBase::mark(byte *root) noexcept {
	assert(root);
	assert(!block(root).mark());

	byte *cur = root;
	byte *prev = nullptr;
	while(true) {
		auto &blk = block(cur);
		if(!blk.mark()) {
			// Mark the object and begin iteration
			blk.ptr() = blk.type().begin();
			blk.ptr().mark(true);
		} else {
			blk.ptr() = blk.ptr().get<const std::ptrdiff_t>() + 1;
		}

		auto offset = *blk.ptr().get<const std::ptrdiff_t>();
		if(offset >= 0) {
			// Advance
			auto &field = *reinterpret_cast<byte**>(cur + offset);
			if(field && !block(field).mark()) {
				auto tmp = std::exchange(field, prev);
				prev = std::exchange(cur, tmp);
			}
		} else {
			// Retreat
			blk.ptr() = reinterpret_cast<const TypeDescriptor*>(
					reinterpret_cast<const byte*>(blk.ptr().get<const std::ptrdiff_t>()) + offset);
			if(!prev) {
				return;
			}
			auto tmp = std::exchange(cur, prev);
			offset = *block(cur).ptr().get<std::ptrdiff_t>();
			prev = std::exchange(*reinterpret_cast<byte**>(cur + offset), tmp);
		}
	} // while(true)
}

// Rebuild the free list while destroying garbage objects
void HeapBase::rebuildFreeList() noexcept {
	Block *freeList = nullptr;

	for(Block *blk = mHeapStart; blk < mHeapEnd;) {
		if(blk->mark()) {
			blk->ptr().mark(false);
			blk = blk->following();

		} else {
			auto free = blk;
			// Extend the free block, destroying garbage objects as necessary
			do {
				if(free->used()) {
					free->type().destroy(free->data());
				}
				free = free->following();
			} while(free < mHeapEnd && !free->mark());

			static_assert(std::is_trivially_destructible<Block>::value, "Block must be trivially destructible.");
			blk->next(freeList, reinterpret_cast<byte*>(free) - reinterpret_cast<byte*>(blk) - Align);
			freeList = blk;
			blk = free;
		}
	}
	mFreeList = freeList;
}

void HeapBase::dump(std::ostream &os) {
	RestoreStream osRestore{os};

	const HeapStats stats = this->collectHeapStats(true);

	os << "==== Statistics for heap at " << std::hex << mHeapStart << std::dec << " ====\n";
	os << "Heap size:  " << stats.heapSize << " bytes\n";
	os << "Used space: " << stats.usedSize << " bytes\n";
	os << "Free space: " << stats.freeSize << " bytes\n";
	os << '\n';
	os << "Object count:    " << stats.numObjects << " (" << stats.numLiveObjects << " live)\n";
	os << "Object size:     " << stats.objectSize << " bytes (" << stats.liveObjectSize << " in live objects)\n";
	os << "Available space: " << stats.freeBlockSize << " bytes in " << stats.numFreeBlocks << " blocks\n";
	os << '\n';
	os << "= Free Blocks =\nAddress    Size(net)\n";

	// Print free blocks: just use the free list
	os.fill('0');
	for(auto blk = mFreeList; blk; blk = blk->next()) {
		os << std::hex << std::setw(sizeof(void*)) << blk
				<< ' ' << std::dec << blk->size() << '\n';
	}
	os << std::setfill(' ') << '\n';

	os << "= Live Objects =\n";
	// For printing live objects we need to do marking
	this->dumpLiveObjects(os);
}

void HeapBase::dumpLiveObjects(std::ostream &os) {
	constexpr std::size_t numDataBytes = 4;
	static const std::string indent(4, ' ');

	for(auto root : mRoots) {
		this->mark(root);
	}
	os << std::hex;
	for(auto blk = mHeapStart; blk < mHeapEnd; blk = blk->following()) {
		if(blk->mark()) {
			blk->ptr().mark(false);
			os << static_cast<void*>(blk->data()) << ' ' << "TODO NAME" << '\n';
			os << "  Data: ";
			std::copy_n(blk->data(), std::min(blk->type().size(), numDataBytes), std::ostream_iterator<int>(os, " "));
			if(blk->type().size() > numDataBytes) {
				os << "...";
			}
			os << "\n  Pointers: ";
			if(blk->type().offsets() > 0) {
				os << "\n";
				for(auto offset : blk->type()) {
					os << indent << *reinterpret_cast<void**>(blk->data() + offset) << '\n';
				}
			} else {
				os << "none\n";
			}
		} // if(blk->mark())
	}
	os << std::dec;
}

HeapBase::HeapStats HeapBase::collectHeapStats(bool countLiveObjects) noexcept {
	HeapStats result{};
	result.heapSize = reinterpret_cast<byte*>(mHeapEnd) - reinterpret_cast<byte*>(mHeapStart);

	if(countLiveObjects) {
		for(auto root : mRoots) {
			this->mark(root);
		}
	}
	for(auto blk = mHeapStart; blk < mHeapEnd; blk = blk->following()) {
		if(blk->free()) {
			result.numFreeBlocks++;
			result.freeBlockSize += blk->size();
			result.freeSize += Align + align(blk->size());
		} else {
			if(blk->mark()) {
				blk->ptr().mark(false);
				result.numLiveObjects++;
				result.liveObjectSize += blk->type().size();
			}
			result.numObjects++;
			result.objectSize += blk->type().size();
			result.usedSize += Align + align(blk->size());
		}
	}
	assert(result.freeSize + result.usedSize == result.heapSize);

	return result;
}

} // namespace ssw
<|endoftext|>


<commit_before>#include "Test.h"
#include "SkDeque.h"

static void assert_count(skiatest::Reporter* reporter, const SkDeque& deq, int count) {
    if (0 == count) {
        REPORTER_ASSERT(reporter, deq.empty());
        REPORTER_ASSERT(reporter, 0 == deq.count());
        REPORTER_ASSERT(reporter, sizeof(int) == deq.elemSize());
        REPORTER_ASSERT(reporter, NULL == deq.front());
        REPORTER_ASSERT(reporter, NULL == deq.back());
    } else {
        REPORTER_ASSERT(reporter, !deq.empty());
        REPORTER_ASSERT(reporter, count == deq.count());
        REPORTER_ASSERT(reporter, sizeof(int) == deq.elemSize());
        REPORTER_ASSERT(reporter, NULL != deq.front());
        REPORTER_ASSERT(reporter, NULL != deq.back());
        if (1 == count) {
            REPORTER_ASSERT(reporter, deq.back() == deq.front());
        } else {
            REPORTER_ASSERT(reporter, deq.back() != deq.front());
        }
    }
}

static void assert_f2biter(skiatest::Reporter* reporter, const SkDeque& deq,
                           int max, int min) {
    SkDeque::F2BIter iter(deq);
    void* ptr;

    int value = max;
    while ((ptr = iter.next()) != NULL) {
        REPORTER_ASSERT(reporter, value == *(int*)ptr);
        value -= 1;
    }
    REPORTER_ASSERT(reporter, value+1 == min);
}

static void TestDeque(skiatest::Reporter* reporter) {
    SkDeque deq(sizeof(int));
    int i;

    assert_count(reporter, deq, 0);
    for (i = 1; i <= 10; i++) {
        *(int*)deq.push_front() = i;
    }
    assert_count(reporter, deq, 10);
    assert_f2biter(reporter, deq, 10, 1);

    for (i = 0; i < 5; i++) {
        deq.pop_front();
    }
    assert_count(reporter, deq, 5);
    assert_f2biter(reporter, deq, 5, 1);

    for (i = 0; i < 5; i++) {
        deq.pop_front();
    }
    assert_count(reporter, deq, 0);
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("Deque", TestDequeClass, TestDeque)
<commit_msg>add tests for pushing on back as well as front<commit_after>#include "Test.h"
#include "SkDeque.h"

static void assert_count(skiatest::Reporter* reporter, const SkDeque& deq, int count) {
    if (0 == count) {
        REPORTER_ASSERT(reporter, deq.empty());
        REPORTER_ASSERT(reporter, 0 == deq.count());
        REPORTER_ASSERT(reporter, sizeof(int) == deq.elemSize());
        REPORTER_ASSERT(reporter, NULL == deq.front());
        REPORTER_ASSERT(reporter, NULL == deq.back());
    } else {
        REPORTER_ASSERT(reporter, !deq.empty());
        REPORTER_ASSERT(reporter, count == deq.count());
        REPORTER_ASSERT(reporter, sizeof(int) == deq.elemSize());
        REPORTER_ASSERT(reporter, NULL != deq.front());
        REPORTER_ASSERT(reporter, NULL != deq.back());
        if (1 == count) {
            REPORTER_ASSERT(reporter, deq.back() == deq.front());
        } else {
            REPORTER_ASSERT(reporter, deq.back() != deq.front());
        }
    }
}

static void assert_f2biter(skiatest::Reporter* reporter, const SkDeque& deq,
                           int max, int min) {
    SkDeque::F2BIter iter(deq);
    void* ptr;

    int value = max;
    while ((ptr = iter.next()) != NULL) {
        REPORTER_ASSERT(reporter, value == *(int*)ptr);
        value -= 1;
    }
    REPORTER_ASSERT(reporter, value+1 == min);
}

static void TestDeque(skiatest::Reporter* reporter) {
    SkDeque deq(sizeof(int));
    int i;

    // test pushing on the front

    assert_count(reporter, deq, 0);
    for (i = 1; i <= 10; i++) {
        *(int*)deq.push_front() = i;
    }
    assert_count(reporter, deq, 10);
    assert_f2biter(reporter, deq, 10, 1);

    for (i = 0; i < 5; i++) {
        deq.pop_front();
    }
    assert_count(reporter, deq, 5);
    assert_f2biter(reporter, deq, 5, 1);

    for (i = 0; i < 5; i++) {
        deq.pop_front();
    }
    assert_count(reporter, deq, 0);

    // now test pushing on the back

    for (i = 10; i >= 1; --i) {
        *(int*)deq.push_back() = i;
    }
    assert_count(reporter, deq, 10);
    assert_f2biter(reporter, deq, 10, 1);

    for (i = 0; i < 5; i++) {
        deq.pop_back();
    }
    assert_count(reporter, deq, 5);
    assert_f2biter(reporter, deq, 10, 6);

    for (i = 0; i < 5; i++) {
        deq.pop_back();
    }
    assert_count(reporter, deq, 0);

    // now tests pushing/poping on both ends

    *(int*)deq.push_front() = 5;
    *(int*)deq.push_back() = 4;
    *(int*)deq.push_front() = 6;
    *(int*)deq.push_back() = 3;
    *(int*)deq.push_front() = 7;
    *(int*)deq.push_back() = 2;
    *(int*)deq.push_front() = 8;
    *(int*)deq.push_back() = 1;
    assert_count(reporter, deq, 8);
    assert_f2biter(reporter, deq, 8, 1);
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("Deque", TestDequeClass, TestDeque)
<|endoftext|>


<commit_before>// -*- mode:c++; indent-tabs-mode:nil; -*-

/*
  Copyright (c) 2014, 2015, Anders Ronnbrant, anders.ronnbrant@gmail.com

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

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

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

#include "Recorder.h"

#include "RecorderSink.h"

#include "zmqutils.h"

#include <boost/program_options.hpp>

#include <zmq.hpp>

#include <atomic>
#include <chrono>
#include <cstdlib>
#include <string>
#include <thread>
#include <vector>

namespace po = boost::program_options;

namespace {
typedef std::chrono::milliseconds msec;
typedef std::chrono::microseconds usec;
typedef std::chrono::nanoseconds  nsec;
}

enum class FOO { A, B, C, D, E, X, Y, Z, Count };
enum class BAR { A, B, C, D, E, X, Y, Z, Count };
enum class FUU { A, B, C, D, E, X, Y, Z, Count };
enum class BER { A, B, C, D, E, X, Y, Z, Count };

template<typename T>
void
funcSetupRecorder(Recorder<T>& rec, char const* prefix, int const id) {
  char name[8][12];

  snprintf(name[0], sizeof(name[0]), "%s-chr%02d", prefix, id);
  snprintf(name[1], sizeof(name[1]), "%s-dbl%02d", prefix, id);
  snprintf(name[2], sizeof(name[2]), "%s-i32%02d", prefix, id);
  snprintf(name[3], sizeof(name[3]), "%s-i64%02d", prefix, id);
  snprintf(name[4], sizeof(name[4]), "%s-uns%02d", prefix, id);
  snprintf(name[5], sizeof(name[5]), "%s-af3%02d", prefix, id);
  snprintf(name[6], sizeof(name[6]), "%s-ad3%02d", prefix, id);
  snprintf(name[7], sizeof(name[7]), "%s-id2%02d", prefix, id);

  // key[enum], name[string], type[enum], description[string], compare[pointer]

  rec.setup(T::A, name[0], "m");
  rec.setup(T::B, name[1], "s");
  rec.setup(T::C, name[2], "C");
  rec.setup(T::D, name[3], "u");
  rec.setup(T::E, name[4], "g");
  rec.setup(T::X, name[5], "-");
  rec.setup(T::Y, name[6], "-");
  rec.setup(T::Z, name[7], "-");
}

template<typename T>
void
funcRecordRecorder(Recorder<T>& rec, int x) {
  float  data1[3] = {500.0f*x, 600.0f*x, 700.0f*x};
  double data2[3] = {500.0*x, 600.0*x, 700.0*x};
  rec.record(T::A, *reinterpret_cast<char*>(&x), x);
  rec.record(T::B, std::log(1+x), x);
  rec.record(T::C, reinterpret_cast<int32_t>(-x*x), x);
  rec.record(T::D, static_cast<int64_t>(-x*x), x);
  rec.record(T::E, static_cast<uint64_t>(x*x), x);
  rec.record(T::X, data1, x);
  rec.record(T::Y, data2, x);
  rec.record(T::Z, {10*x, 20*x}, x);
}

void funcProducer(int const id, int const num_rounds) {
  std::string prefix;
  char recorder_name[32];

  prefix = "FOO";
  snprintf(recorder_name, sizeof(recorder_name), "%s%02d", prefix.c_str() , id);
  Recorder<FOO> recfoo(recorder_name, random() % (1<<16));
  funcSetupRecorder(recfoo, prefix.c_str(), id);

  prefix = "BAR";
  snprintf(recorder_name, sizeof(recorder_name), "%s%02d", prefix.c_str() , id);
  Recorder<BAR> recbar(recorder_name, random() % (1<<16));
  funcSetupRecorder(recbar, prefix.c_str(), id);

  prefix = "FUU";
  snprintf(recorder_name, sizeof(recorder_name), "%s%02d", prefix.c_str() , id);
  Recorder<FUU> recfuu(recorder_name, random() % (1<<16));
  funcSetupRecorder(recfuu, prefix.c_str(), id);

  prefix = "BER";
  snprintf(recorder_name, sizeof(recorder_name), "%s%02d", prefix.c_str() , id);
  Recorder<BER> recber(recorder_name, random() % (1<<16));
  funcSetupRecorder(recber, prefix.c_str(), id);

  for (int j = 0; j < num_rounds; ++j) {
    //std::this_thread::sleep_for(nsec(10));
    funcRecordRecorder(recfoo, j);
    funcRecordRecorder(recbar, j);
    funcRecordRecorder(recfuu, j);
    funcRecordRecorder(recber, j);
  }
}

int
main(int ac, char** av) {
  int num_rec_rounds  = 2;
  int num_rec_threads = 2;
  int num_ctx_threads = 1;
  std::string addr = "inproc://recorder";

  // ----------------------------------------------------------------------
  po::options_description opts("Options", 80, 75);
  opts.add_options()
      ("help,h", "Show help")
      ("verbose,v", "Be verbose")
      ("rounds,r",
       po::value<int>(&num_rec_rounds)->default_value(num_rec_rounds),
       "Number of recording rounds")
      ("threads,t",
       po::value<int>(&num_rec_threads)->default_value(num_rec_threads),
       "Number of recording threads. Producer threads that records 8 "
       "different values per round.")
      ("context_io",
       po::value<int>(&num_ctx_threads)->default_value(num_ctx_threads),
       "Number of ZMQ context io threads. Defaults to one (1) and should "
       "almost always be that.")
      ("address,a",
       po::value<std::string>(&addr)->default_value(addr),
       "Socket address");

  po::variables_map vm;
  po::store(po::parse_command_line(ac, av, opts), vm);
  po::notify(vm);

  if (vm.count("help")) {
    opts.print(std::cout);
    std::exit(0);
  }
  // ----------------------------------------------------------------------

  zmq::context_t ctx(num_ctx_threads);

  RecorderBase::setContext(&ctx);
  RecorderBase::setAddress(addr);

  printf("PID:       %d\n", getpid());
  printf("Item size: %lu\n", sizeof(Item));

  RecorderSink backend;
  backend.start(vm.count("verbose"));

  int const num_recorder_per_thread = 4;
  int const num_messages_per_recorder = 8;

  // Each item recording generates two messages per round except for the
  // first, which only creates a single message.
  auto num_messages = num_rec_threads *
                      num_recorder_per_thread *
                      num_messages_per_recorder *
                      (2 * num_rec_rounds - 1);

  printf("Running %d threads %d rounds\n"
         "  %d recorders per thread\n"
         "  %d items per recorder\n"
         "Total %d (%ldMiB)\n",
         num_rec_threads,
         num_rec_rounds,
         num_recorder_per_thread,
         num_messages_per_recorder,
         num_messages,
         (num_messages * sizeof(Item))/(1024*1024));

  std::vector<std::thread> recorders;
  for (int i = 0; i < num_rec_threads; ++i) {
    recorders.emplace_back(std::thread(&funcProducer, i+1, num_rec_rounds));
  }

  for (auto& th : recorders) {
    if (th.joinable())
      th.join();
  }

  std::this_thread::sleep_for(msec(1));

  backend.stop();

  RecorderBase::shutDown();

  return 0;
}
<commit_msg>Adjust producer data, less recorders and different values<commit_after>// -*- mode:c++; indent-tabs-mode:nil; -*-

/*
  Copyright (c) 2014, 2015, Anders Ronnbrant, anders.ronnbrant@gmail.com

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

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

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

#include "Recorder.h"

#include "RecorderSink.h"

#include "zmqutils.h"

#include <boost/program_options.hpp>

#include <zmq.hpp>

#include <atomic>
#include <chrono>
#include <cstdlib>
#include <string>
#include <thread>
#include <vector>

namespace po = boost::program_options;

namespace {
typedef std::chrono::milliseconds msec;
typedef std::chrono::microseconds usec;
typedef std::chrono::nanoseconds  nsec;
}

enum class FOO { A, B, C, D, E, X, Y, Z, Count };
enum class BAR { A, B, C, D, E, X, Y, Z, Count };
enum class FUU { A, B, C, D, E, X, Y, Z, Count };
enum class BER { A, B, C, D, E, X, Y, Z, Count };

template<typename T>
void
funcSetupRecorder(Recorder<T>& rec, char const* prefix, int const id) {
  char name[8][12];

  snprintf(name[0], sizeof(name[0]), "%s-chr%02d", prefix, id);
  snprintf(name[1], sizeof(name[1]), "%s-dbl%02d", prefix, id);
  snprintf(name[2], sizeof(name[2]), "%s-i32%02d", prefix, id);
  snprintf(name[3], sizeof(name[3]), "%s-i64%02d", prefix, id);
  snprintf(name[4], sizeof(name[4]), "%s-uns%02d", prefix, id);
  snprintf(name[5], sizeof(name[5]), "%s-af3%02d", prefix, id);
  snprintf(name[6], sizeof(name[6]), "%s-ad3%02d", prefix, id);
  snprintf(name[7], sizeof(name[7]), "%s-id2%02d", prefix, id);

  // key[enum], name[string], type[enum], description[string], compare[pointer]

  rec.setup(T::A, name[0], "m");
  rec.setup(T::B, name[1], "s");
  rec.setup(T::C, name[2], "C");
  rec.setup(T::D, name[3], "u");
  rec.setup(T::E, name[4], "g");
  rec.setup(T::X, name[5], "-");
  rec.setup(T::Y, name[6], "-");
  rec.setup(T::Z, name[7], "-");
}

template<typename T>
void
funcRecordRecorder(Recorder<T>& rec, int x) {
  float  data1[3] = {500.0f*x, 600.0f*x, 700.0f*x};
  double data2[3] = {500.0*x, 600.0*x, 700.0*x};
  rec.record(T::A, *reinterpret_cast<char*>(&x), x);
  rec.record(T::B, std::log(2+x), x);
  rec.record(T::C, reinterpret_cast<int32_t>(-1), x);
  rec.record(T::D, static_cast<int64_t>(-2+x), x);
  rec.record(T::E, static_cast<uint64_t>(2*(1+x)), x);
  rec.record(T::X, data1, x);
  rec.record(T::Y, data2, x);
  rec.record(T::Z, {10*(1+x), 20*(1+x)}, x);
}

void funcProducer(int const id, int const num_rounds) {
  std::string prefix;
  char recorder_name[32];

  prefix = "FOO";
  snprintf(recorder_name, sizeof(recorder_name), "%s%02d", prefix.c_str() , id);
  Recorder<FOO> recfoo(recorder_name, random() % (1<<16));
  funcSetupRecorder(recfoo, prefix.c_str(), id);

  //prefix = "BAR";
  //snprintf(recorder_name, sizeof(recorder_name), "%s%02d", prefix.c_str() , id);
  //Recorder<BAR> recbar(recorder_name, random() % (1<<16));
  //funcSetupRecorder(recbar, prefix.c_str(), id);

  for (int j = 0; j < num_rounds; ++j) {
    std::this_thread::sleep_for(nsec(1));
    funcRecordRecorder(recfoo, j);
    //funcRecordRecorder(recbar, j);
  }
}

int
main(int ac, char** av) {
  int num_rec_rounds  = 2;
  int num_rec_threads = 2;
  int num_ctx_threads = 1;
  std::string addr = "inproc://recorder";

  // ----------------------------------------------------------------------
  po::options_description opts("Options", 80, 75);
  opts.add_options()
      ("help,h", "Show help")
      ("verbose,v", "Be verbose")
      ("rounds,r",
       po::value<int>(&num_rec_rounds)->default_value(num_rec_rounds),
       "Number of recording rounds")
      ("threads,t",
       po::value<int>(&num_rec_threads)->default_value(num_rec_threads),
       "Number of recording threads. Producer threads that records 8 "
       "different values per round.")
      ("context_io",
       po::value<int>(&num_ctx_threads)->default_value(num_ctx_threads),
       "Number of ZMQ context io threads. Defaults to one (1) and should "
       "almost always be that.")
      ("address,a",
       po::value<std::string>(&addr)->default_value(addr),
       "Socket address");

  po::variables_map vm;
  po::store(po::parse_command_line(ac, av, opts), vm);
  po::notify(vm);

  if (vm.count("help")) {
    opts.print(std::cout);
    std::exit(0);
  }
  // ----------------------------------------------------------------------

  zmq::context_t ctx(num_ctx_threads);

  RecorderBase::setContext(&ctx);
  RecorderBase::setAddress(addr);

  printf("PID:       %d\n", getpid());
  printf("Item size: %lu\n", sizeof(Item));

  RecorderSink backend;
  backend.start(vm.count("verbose"));

  int const num_recorder_per_thread = 2;
  int const num_messages_per_recorder = 8;

  // Each item recording generates two messages per round except for the
  // first, which only creates a single message.
  auto num_messages = num_rec_threads *
                      num_recorder_per_thread *
                      num_messages_per_recorder *
                      (2 * num_rec_rounds - 1);

  printf("Running %d threads %d rounds\n"
         "  %d recorders per thread\n"
         "  %d items per recorder\n"
         "Total %d (%ldMiB)\n",
         num_rec_threads,
         num_rec_rounds,
         num_recorder_per_thread,
         num_messages_per_recorder,
         num_messages,
         (num_messages * sizeof(Item))/(1024*1024));

  std::vector<std::thread> recorders;
  for (int i = 0; i < num_rec_threads; ++i) {
    recorders.emplace_back(std::thread(&funcProducer, i+1, num_rec_rounds));
  }

  for (auto& th : recorders) {
    if (th.joinable())
      th.join();
  }

  std::this_thread::sleep_for(msec(1));

  backend.stop();

  RecorderBase::shutDown();

  return 0;
}
<|endoftext|>


<commit_before>//
// This file is a part of pomerol - a scientific ED code for obtaining
// properties of a Hubbard model on a finite-size lattice
//
// Copyright (C) 2010-2012 Andrey Antipov <antipov@ct-qmc.org>
// Copyright (C) 2010-2012 Igor Krivenko <igor@shg.ru>
//
// pomerol is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pomerol is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pomerol.  If not, see <http://www.gnu.org/licenses/>.

/** \file tests/IndexTerm.cpp
** \brief Test of the IndexHamiltonian::Term.
**
** \author Andrey Antipov (Andrey.E.Antipov@gmail.com)
*/

#include "Misc.h"
#include "Logger.h"
#include "Index.h"
#include "IndexClassification.h"
#include "IndexHamiltonian.h"
#include <boost/shared_ptr.hpp>

using namespace Pomerol;

int main(int argc, char* argv[])
{
  /* Test of IndexHamiltonian::Term*/
  Log.setDebugging(true);
  bool Seq[4] = {0,0,1,0};
  ParticleIndex Ind[] = {1,2,2,4};
  std::vector<bool> seq_v(Seq, Seq+4);
  std::vector<ParticleIndex> ind_v(Ind, Ind+4);
  IndexHamiltonian::Term IT1(4, seq_v, ind_v, 1.0);
  INFO("Created IndexHamiltonian::Term" << IT1);
  INFO("Rearranging it to normal order");
  boost::shared_ptr<std::list<IndexHamiltonian::Term*> > out_terms=IT1.makeNormalOrder();
  INFO("Received " << IT1);
  INFO(out_terms->size() << " additional terms emerged : ");
  for (std::list<IndexHamiltonian::Term*>::const_iterator it1=out_terms->begin(); it1!=out_terms->end(); ++it1) DEBUG(**it1);
  /* end of test of IndexHamiltonian::Term */

  return EXIT_SUCCESS;
}

<commit_msg>minor upd<commit_after>//
// This file is a part of pomerol - a scientific ED code for obtaining
// properties of a Hubbard model on a finite-size lattice
//
// Copyright (C) 2010-2012 Andrey Antipov <antipov@ct-qmc.org>
// Copyright (C) 2010-2012 Igor Krivenko <igor@shg.ru>
//
// pomerol is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pomerol is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pomerol.  If not, see <http://www.gnu.org/licenses/>.

/** \file tests/IndexTerm.cpp
** \brief Test of the IndexHamiltonian::Term.
**
** \author Andrey Antipov (Andrey.E.Antipov@gmail.com)
*/

#include "Misc.h"
#include "Logger.h"
#include "Index.h"
#include "IndexClassification.h"
#include "IndexHamiltonian.h"
#include <boost/shared_ptr.hpp>

using namespace Pomerol;

int main(int argc, char* argv[])
{
  /* Test of IndexHamiltonian::Term*/
  Log.setDebugging(true);
  bool Seq[4] = {0,0,1,0};
  ParticleIndex Ind[] = {1,2,2,4};
  std::vector<bool> seq_v(Seq, Seq+4);
  std::vector<ParticleIndex> ind_v(Ind, Ind+4);
  IndexHamiltonian::Term IT1(4, seq_v, ind_v, 1.0);
  INFO("Created IndexHamiltonian::Term" << IT1);
  INFO("Rearranging it to normal order");
  try {
    boost::shared_ptr<std::list<IndexHamiltonian::Term*> > out_terms=IT1.makeNormalOrder();
    INFO("Received " << IT1);
    INFO(out_terms->size() << " additional terms emerged : ");
    for (std::list<IndexHamiltonian::Term*>::const_iterator it1=out_terms->begin(); it1!=out_terms->end(); ++it1) DEBUG(**it1);
    }
  catch (std::exception &e)
    {
        return EXIT_FAILURE;
    }
  /* end of test of IndexHamiltonian::Term */

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>
#include "TestRunner.h"
#include "TestBenchmark.h"

#include "JSON/JSON.h"

using namespace Tundra;
using namespace Tundra::Test;

const String StringData = "\"  Json String Test\tHello World  \"";
const String ObjectData = "{\n\"Hello\":true  ,   \"World\"  \n:  00010, \"Str\" :" + StringData + "  }";
const String ArrayData  = "[ \"Hello World\", 0  ,-1234,   1234.5678  ,  true,false,   \n   null, [ \"World Hello\", 10, false ]  \t , " + ObjectData + "  \n]";

TEST_F(Runner, ParseJSON)
{
    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("String", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(StringData));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_STRING);
        ASSERT_TRUE(value.IsString());

        ASSERT_EQ(value.GetString(), "  Json String Test\tHello World  ");
    }
    BENCHMARK_END;

    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("Array", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(ArrayData));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_ARRAY);
        ASSERT_TRUE(value.IsArray());

        ASSERT_EQ(value[0].GetString(), "Hello World");
        ASSERT_DOUBLE_EQ(value[1].GetNumber(), 0.0);
        ASSERT_DOUBLE_EQ(value[2].GetNumber(), -1234.0);
        ASSERT_DOUBLE_EQ(value[3].GetNumber(), 1234.5678);
        ASSERT_TRUE(value[4].GetBool());
        ASSERT_FALSE(value[5].GetBool());
        ASSERT_TRUE(value[6].IsNull());

        // Embedded array
        ASSERT_TRUE(value[7].IsArray());
        ASSERT_TRUE(value[7][0].IsString());
        ASSERT_TRUE(value[7][1].IsNumber());
        ASSERT_TRUE(value[7][2].IsBool());

        // Embedded object
        ASSERT_TRUE(value[8].IsObject());
        JSONObject obj = value[8].GetObject();
        ASSERT_TRUE(obj["Hello"].IsBool() && obj["Hello"].GetBool());
        ASSERT_TRUE(obj["World"].IsNumber());
        ASSERT_DOUBLE_EQ(obj["World"].GetNumber(), 10.0);
        ASSERT_TRUE(obj["Str"].IsString());
        ASSERT_EQ(obj["Str"].GetString().Length(), StringData.Length() - 2);
    }
    BENCHMARK_END;

    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("Object", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(ObjectData));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_OBJECT);
        ASSERT_TRUE(value.IsObject());

        JSONObject obj = value.GetObject();
        ASSERT_TRUE(obj["Hello"].IsBool() && obj["Hello"].GetBool());
        ASSERT_TRUE(obj["World"].IsNumber());
        ASSERT_DOUBLE_EQ(obj["World"].GetNumber(), 10.0);
        ASSERT_TRUE(obj["Str"].IsString());
        ASSERT_EQ(obj["Str"].GetString().Length(), StringData.Length() - 2);
    }
    BENCHMARK_END;
}

TUNDRA_TEST_MAIN();
<commit_msg>Expand JSON tests for Null, Number, Bool. Embed both array and object to array and object test data.<commit_after>
#include "TestRunner.h"
#include "TestBenchmark.h"

#include "JSON/JSON.h"

using namespace Tundra;
using namespace Tundra::Test;

const String StringData = "\"  Json String Test\tHello World  \"";
const String ObjectData = "{\n\"Hello\":true  ,   \"World\"  \n:  00010, \"Str\" :" + StringData + " , \"Arr\" : [1,2],\"Obj\":{\"test\" : true}  }";
const String ArrayData  = "[ \"Hello World\", 0  ,-1234,   1234.5678  ,  true,false,   \n   null, [ \"World Hello\", 10, false ]  \t , " + ObjectData + "  \n]";

TEST_F(Runner, ParseJSON)
{
    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("Null", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(" \t \n     null   "));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_NULL);
        ASSERT_TRUE(value.IsNull());
    }
    BENCHMARK_END;

    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("Bool", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(" \t \n     true   "));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_BOOL);
        ASSERT_TRUE(value.IsBool());
        ASSERT_TRUE(value.GetBool());
    }
    BENCHMARK_END;

    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("Number", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString("  \n    1238972313.12312412   "));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_NUMBER);
        ASSERT_TRUE(value.IsNumber());
        ASSERT_DOUBLE_EQ(value.GetNumber(), 1238972313.12312412);
    }
    BENCHMARK_END;

    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("String", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(StringData));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_STRING);
        ASSERT_TRUE(value.IsString());

        ASSERT_EQ(value.GetString(), "  Json String Test\tHello World  ");
    }
    BENCHMARK_END;

    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("Array", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(ArrayData));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_ARRAY);
        ASSERT_TRUE(value.IsArray());

        ASSERT_EQ(value[0].GetString(), "Hello World");
        ASSERT_DOUBLE_EQ(value[1].GetNumber(), 0.0);
        ASSERT_DOUBLE_EQ(value[2].GetNumber(), -1234.0);
        ASSERT_DOUBLE_EQ(value[3].GetNumber(), 1234.5678);
        ASSERT_TRUE(value[4].GetBool());
        ASSERT_FALSE(value[5].GetBool());
        ASSERT_TRUE(value[6].IsNull());

        // Embedded array
        ASSERT_TRUE(value[7].IsArray());
        ASSERT_TRUE(value[7][0].IsString());
        ASSERT_TRUE(value[7][1].IsNumber());
        ASSERT_TRUE(value[7][2].IsBool());

        // Embedded object
        ASSERT_TRUE(value[8].IsObject());
        JSONObject obj = value[8].GetObject();
        ASSERT_TRUE(obj["Hello"].IsBool() && obj["Hello"].GetBool());
        ASSERT_TRUE(obj["World"].IsNumber());
        ASSERT_DOUBLE_EQ(obj["World"].GetNumber(), 10.0);
        ASSERT_TRUE(obj["Str"].IsString());
        ASSERT_EQ(obj["Str"].GetString().Length(), StringData.Length() - 2);
        // Embedded child array
        ASSERT_TRUE(obj["Arr"].IsArray());
        ASSERT_EQ(obj["Arr"].GetArray()[1], 2);
        // Embedded child Object
        ASSERT_TRUE(obj["Obj"].IsObject());
        JSONObject childObj = obj["Obj"].GetObject();
        ASSERT_TRUE(childObj["test"].GetBool());
    }
    BENCHMARK_END;

    Tundra::Benchmark::Iterations = 10000;

    BENCHMARK("Object", 10)
    {
        JSONValue value;

        ASSERT_TRUE(value.FromString(ObjectData));
        BENCHMARK_STEP_END;

        ASSERT_EQ(value.Type(), JSON_OBJECT);
        ASSERT_TRUE(value.IsObject());

        JSONObject obj = value.GetObject();
        ASSERT_TRUE(obj["Hello"].IsBool() && obj["Hello"].GetBool());
        ASSERT_TRUE(obj["World"].IsNumber());
        ASSERT_DOUBLE_EQ(obj["World"].GetNumber(), 10.0);
        ASSERT_TRUE(obj["Str"].IsString());
        ASSERT_EQ(obj["Str"].GetString().Length(), StringData.Length() - 2);
        // Embedded array
        ASSERT_TRUE(obj["Arr"].IsArray());
        ASSERT_EQ(obj["Arr"].GetArray()[1], 2);
        // Embedded Object
        ASSERT_TRUE(obj["Obj"].IsObject());
        JSONObject childObj = obj["Obj"].GetObject();
        ASSERT_TRUE(childObj["test"].GetBool());
    }
    BENCHMARK_END;
}

TUNDRA_TEST_MAIN();
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(UtestShell)
{
    TestTestingFixture fixture;
};

static void _failMethod()
{
    FAIL("This test fails");
}

static void _passingTestMethod()
{
    CHECK(true);
}

static void _passingCheckEqualTestMethod()
{
    CHECK_EQUAL(1, 1);
}

TEST(UtestShell, compareDoubles)
{
    double zero = 0.0;
    double not_a_number = zero / zero;
    CHECK(doubles_equal(1.0, 1.001, 0.01));
    CHECK(!doubles_equal(not_a_number, 1.001, 0.01));
    CHECK(!doubles_equal(1.0, not_a_number, 0.01));
    CHECK(!doubles_equal(1.0, 1.001, not_a_number));
    CHECK(!doubles_equal(1.0, 1.1, 0.05));

    double a = 1.2345678;
    CHECK(doubles_equal(a, a, 0.000000001));
}

TEST(UtestShell, FailWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_passingCheckEqualTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture)
{
    CHECK(&fixture != 0);
}

TEST(UtestShell, MacrosUsedInSetup)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setSetup(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

TEST(UtestShell, MacrosUsedInTearDown)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

static int teardownCalled = 0;

static void _teardownMethod()
{
    teardownCalled++;
}

TEST(UtestShell, TeardownCalledAfterTestFailure)
{
    teardownCalled = 0;
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_teardownMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(1, teardownCalled);
}

static int stopAfterFailure = 0;
static void _stopAfterFailureMethod()
{
    FAIL("fail");
    stopAfterFailure++;
}

TEST(UtestShell, TestStopsAfterTestFailure)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    stopAfterFailure = 0;
    fixture.setTestFunction(_stopAfterFailureMethod);
    fixture.runAllTests();
    CHECK(fixture.hasTestFailed());
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

TEST(UtestShell, TestStopsAfterSetupFailure)
{
    stopAfterFailure = 0;
    fixture.setSetup(_stopAfterFailureMethod);
    fixture.setTeardown(_stopAfterFailureMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

class defaultUtestShell: public UtestShell
{
};

TEST(UtestShell, this_test_covers_the_UtestShell_createTest_and_Utest_testBody_methods)
{
    defaultUtestShell shell;
    fixture.addTest(&shell);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.result_->getTestCount());
}

static void StubPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
    result->addFailure(TestFailure(shell, "Failed in separate process"));
}

TEST(UtestShell, RunInSeparateProcessTest)
{
    UT_PTR_SET(PlatformSpecificRunTestInASeperateProcess, StubPlatformSpecificRunTestInASeperateProcess);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process");
}

#if !defined(__MINGW32__) && !defined(_MSC_VER)

TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest)
{
    fixture.setTestFunction(UtestShell::crash);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process - killed by signal 11");
}

#else

IGNORE_TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest) {}

#endif

#if CPPUTEST_USE_STD_CPP_LIB

static bool destructorWasCalledOnFailedTest = false;

static void _destructorCalledForLocalObjects()
{
    SetBooleanOnDestructorCall pleaseCallTheDestructor(destructorWasCalledOnFailedTest);
    destructorWasCalledOnFailedTest = false;
    FAIL("fail");
}

TEST(UtestShell, DestructorIsCalledForLocalObjectsWhenTheTestFails)
{
    fixture.setTestFunction(_destructorCalledForLocalObjects);
    fixture.runAllTests();
    CHECK(destructorWasCalledOnFailedTest);
}

#endif

TEST_BASE(MyOwnTest)
{
    MyOwnTest() :
        inTest(false)
    {
    }
    bool inTest;

    void setup()
    {
        CHECK(!inTest);
        inTest = true;
    }
    void teardown()
    {
        CHECK(inTest);
        inTest = false;
    }
};

TEST_GROUP_BASE(UtestMyOwn, MyOwnTest)
{
};

TEST(UtestMyOwn, test)
{
    CHECK(inTest);
}

class NullParameterTest: public UtestShell
{
};

TEST(UtestMyOwn, NullParameters)
{
    NullParameterTest nullTest; /* Bug fix tests for creating a test without a name, fix in SimpleString */
    TestFilter emptyFilter;
    CHECK(nullTest.shouldRun(&emptyFilter, &emptyFilter));
}

class AllocateAndDeallocateInConstructorAndDestructor
{
    char* memory_;
    char* morememory_;
public:
    AllocateAndDeallocateInConstructorAndDestructor()
    {
        memory_ = new char[100];
        morememory_ = NULL;
    }
    void allocateMoreMemory()
    {
        morememory_ = new char[123];
    }

    ~AllocateAndDeallocateInConstructorAndDestructor()
    {
        delete [] memory_;
        delete [] morememory_;
    }
};

TEST_GROUP(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks)
{
    AllocateAndDeallocateInConstructorAndDestructor dummy;
};

TEST(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks, testInTestGroupName)
{
    dummy.allocateMoreMemory();
}

<commit_msg>Just had to get the 100% back...<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(Utest)
{
};

TEST(Utest, division)
{
    LONGS_EQUAL(3, division(13, 4));
}

TEST_GROUP(UtestShell)
{
    TestTestingFixture fixture;
};

static void _failMethod()
{
    FAIL("This test fails");
}

static void _passingTestMethod()
{
    CHECK(true);
}

static void _passingCheckEqualTestMethod()
{
    CHECK_EQUAL(1, 1);
}

TEST(UtestShell, compareDoubles)
{
    double zero = 0.0;
    double not_a_number = zero / zero;
    CHECK(doubles_equal(1.0, 1.001, 0.01));
    CHECK(!doubles_equal(not_a_number, 1.001, 0.01));
    CHECK(!doubles_equal(1.0, not_a_number, 0.01));
    CHECK(!doubles_equal(1.0, 1.001, not_a_number));
    CHECK(!doubles_equal(1.0, 1.1, 0.05));

    double a = 1.2345678;
    CHECK(doubles_equal(a, a, 0.000000001));
}

TEST(UtestShell, FailWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_passingCheckEqualTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture)
{
    CHECK(&fixture != 0);
}

TEST(UtestShell, MacrosUsedInSetup)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setSetup(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

TEST(UtestShell, MacrosUsedInTearDown)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

static int teardownCalled = 0;

static void _teardownMethod()
{
    teardownCalled++;
}

TEST(UtestShell, TeardownCalledAfterTestFailure)
{
    teardownCalled = 0;
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_teardownMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(1, teardownCalled);
}

static int stopAfterFailure = 0;
static void _stopAfterFailureMethod()
{
    FAIL("fail");
    stopAfterFailure++;
}

TEST(UtestShell, TestStopsAfterTestFailure)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    stopAfterFailure = 0;
    fixture.setTestFunction(_stopAfterFailureMethod);
    fixture.runAllTests();
    CHECK(fixture.hasTestFailed());
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

TEST(UtestShell, TestStopsAfterSetupFailure)
{
    stopAfterFailure = 0;
    fixture.setSetup(_stopAfterFailureMethod);
    fixture.setTeardown(_stopAfterFailureMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

class defaultUtestShell: public UtestShell
{
};

TEST(UtestShell, this_test_covers_the_UtestShell_createTest_and_Utest_testBody_methods)
{
    defaultUtestShell shell;
    fixture.addTest(&shell);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.result_->getTestCount());
}

static void StubPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
    result->addFailure(TestFailure(shell, "Failed in separate process"));
}

TEST(UtestShell, RunInSeparateProcessTest)
{
    UT_PTR_SET(PlatformSpecificRunTestInASeperateProcess, StubPlatformSpecificRunTestInASeperateProcess);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process");
}

#if !defined(__MINGW32__) && !defined(_MSC_VER)

TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest)
{
    fixture.setTestFunction(UtestShell::crash);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process - killed by signal 11");
}

#else

IGNORE_TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest) {}

#endif

#if CPPUTEST_USE_STD_CPP_LIB

static bool destructorWasCalledOnFailedTest = false;

static void _destructorCalledForLocalObjects()
{
    SetBooleanOnDestructorCall pleaseCallTheDestructor(destructorWasCalledOnFailedTest);
    destructorWasCalledOnFailedTest = false;
    FAIL("fail");
}

TEST(UtestShell, DestructorIsCalledForLocalObjectsWhenTheTestFails)
{
    fixture.setTestFunction(_destructorCalledForLocalObjects);
    fixture.runAllTests();
    CHECK(destructorWasCalledOnFailedTest);
}

#endif

TEST_BASE(MyOwnTest)
{
    MyOwnTest() :
        inTest(false)
    {
    }
    bool inTest;

    void setup()
    {
        CHECK(!inTest);
        inTest = true;
    }
    void teardown()
    {
        CHECK(inTest);
        inTest = false;
    }
};

TEST_GROUP_BASE(UtestMyOwn, MyOwnTest)
{
};

TEST(UtestMyOwn, test)
{
    CHECK(inTest);
}

class NullParameterTest: public UtestShell
{
};

TEST(UtestMyOwn, NullParameters)
{
    NullParameterTest nullTest; /* Bug fix tests for creating a test without a name, fix in SimpleString */
    TestFilter emptyFilter;
    CHECK(nullTest.shouldRun(&emptyFilter, &emptyFilter));
}

class AllocateAndDeallocateInConstructorAndDestructor
{
    char* memory_;
    char* morememory_;
public:
    AllocateAndDeallocateInConstructorAndDestructor()
    {
        memory_ = new char[100];
        morememory_ = NULL;
    }
    void allocateMoreMemory()
    {
        morememory_ = new char[123];
    }

    ~AllocateAndDeallocateInConstructorAndDestructor()
    {
        delete [] memory_;
        delete [] morememory_;
    }
};

TEST_GROUP(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks)
{
    AllocateAndDeallocateInConstructorAndDestructor dummy;
};

TEST(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks, testInTestGroupName)
{
    dummy.allocateMoreMemory();
}

<|endoftext|>


<commit_before>#ifndef RESPONSE_HPP_INCLUDED
#define RESPONSE_HPP_INCLUDED

#include "forward.hpp"
#include "connection.hpp"
#include "response_header.hpp"

#include <string>
#include <memory>

namespace Rest {
    class Response
    {
        friend InterfaceProvider;

    public:
        /**
         *  Sends a string back to the client.
         *
         *  @param message The string to send.
         */
        void send(std::string const& message);

        /**
         *  Stringifies an object and sends it back to the client.
         *
         *  @param obj The object to stringify and send.
         */
        template <typename T>
        void json(T const& obj)
        {
            connection_->sendJson(obj, header_);
        }

        /**
         *  Alias for json.
         *  @see json
         */
        template <typename T>
        void sendJson(T const& obj)
        {
            json(obj, header_);
        }

        /**
         *  Sends a file back to the client.
         *
         *  @param fileName A file to send.
         *  @param responseHeader A response header containing header information,
         *         such as response code, version and response message.
         */
        void sendFile(std::string const& fileName, bool autoDetectContentType = true);

        /**
         *  Sends a status code with the string representation as body.
         *  Equivalent to status(code).send(...)
         *
         *  status(403).send("Forbidden")
         *
         *  @param code A standard HTTP response code.
         */
        void sendStatus(int code);

        /**
         *  Used for empty bodies. This is actually a 'no operation' function,
         *  because things a finished, when your handler returns.
         *  But it might transform send functions into nop's the future.
         */
        void end();

        /**
         *  Sets the status code for the next send.
         *  Please not that the code defaults to 200 or 204 if not specified!
         *  This method is intended to be chained!
         *
         *  @param code A standard HTTP response code.
         *
         *  @return itself.
         */
        Response& status(int code);

        /**
         *  Sets a header key value pair. Adds it if it were not existing.
         *  Does not perform checkings. Make sure to do it correctly.
         *
         *  @param key Key of header entry.
         *  @param value Value of header entry.
         *
         *  @return itself.
         */
        Response& setHeaderEntry(std::string key, std::string value);

        /**
         *  Redirects to another url / page.
         *  Sets the Location header entry for that. The status code will default
         *  to 302. Another code you should look into is 301.
         *
         *  @param path The path to redirect to. See HTTP Location header field.
         */
        void redirect(std::string const& path);

        /**
         *  Returns the connection to the client.
         *  Can be useful to access more delicate and low level things.
         *  Please do not abuse!
         *
         *  @return Returns a RestConnection reference
         */
        RestConnection& getConnection();

    private:
        // cannot be created by user.
        Response(std::shared_ptr <RestConnection>& connection);

    private:
        std::shared_ptr <RestConnection> connection_;
        ResponseHeader header_;
        bool statusSet_;
    };
}

#endif // RESPONSE_HPP_INCLUDED
<commit_msg>Its possible to send empty messages, meaning no body, but a header.<commit_after>#ifndef RESPONSE_HPP_INCLUDED
#define RESPONSE_HPP_INCLUDED

#include "forward.hpp"
#include "connection.hpp"
#include "response_header.hpp"

#include <string>
#include <memory>

namespace Rest {
    class Response
    {
        friend InterfaceProvider;

    public:
        /**
         *  Sends a string back to the client.
         *
         *  @param message The string to send.
         */
        void send(std::string const& message = "");

        /**
         *  Stringifies an object and sends it back to the client.
         *
         *  @param obj The object to stringify and send.
         */
        template <typename T>
        void json(T const& obj)
        {
            connection_->sendJson(obj, header_);
        }

        /**
         *  Alias for json.
         *  @see json
         */
        template <typename T>
        void sendJson(T const& obj)
        {
            json(obj, header_);
        }

        /**
         *  Sends a file back to the client.
         *
         *  @param fileName A file to send.
         *  @param responseHeader A response header containing header information,
         *         such as response code, version and response message.
         */
        void sendFile(std::string const& fileName, bool autoDetectContentType = true);

        /**
         *  Sends a status code with the string representation as body.
         *  Equivalent to status(code).send(...)
         *
         *  status(403).send("Forbidden")
         *
         *  @param code A standard HTTP response code.
         */
        void sendStatus(int code);

        /**
         *  Used for empty bodies. This is actually a 'no operation' function,
         *  because things a finished, when your handler returns.
         *  But it might transform send functions into nop's the future.
         */
        void end();

        /**
         *  Sets the status code for the next send.
         *  Please not that the code defaults to 200 or 204 if not specified!
         *  This method is intended to be chained!
         *
         *  @param code A standard HTTP response code.
         *
         *  @return itself.
         */
        Response& status(int code);

        /**
         *  Sets a header key value pair. Adds it if it were not existing.
         *  Does not perform checkings. Make sure to do it correctly.
         *
         *  @param key Key of header entry.
         *  @param value Value of header entry.
         *
         *  @return itself.
         */
        Response& setHeaderEntry(std::string key, std::string value);

        /**
         *  Redirects to another url / page.
         *  Sets the Location header entry for that. The status code will default
         *  to 302. Another code you should look into is 301.
         *
         *  @param path The path to redirect to. See HTTP Location header field.
         */
        void redirect(std::string const& path);

        /**
         *  Sets the content type. such as "application/json".
         *  if the passed type is a file extension (without dot), it will choose the correct type.
         *  Check mime.cpp for a list of known extensions.
         *
         *  @param type custom Content-Type or file extension.
         */
        Response& type(std::string const& type);

        /**
         *  Returns the connection to the client.
         *  Can be useful to access more delicate and low level things.
         *  Please do not abuse!
         *
         *  @return Returns a RestConnection reference
         */
        RestConnection& getConnection();

    private:
        // cannot be created by user.
        Response(std::shared_ptr <RestConnection>& connection);

    private:
        std::shared_ptr <RestConnection> connection_;
        ResponseHeader header_;
        bool statusSet_;
    };
}

#endif // RESPONSE_HPP_INCLUDED
<|endoftext|>


<commit_before>#ifndef RECURSE_RESPONSE_HPP
#define RECURSE_RESPONSE_HPP

#include <QHash>
#include <QJsonDocument>
#include <functional>

class Response {

public:

    QString get(const QString &key) { return header[key]; };
    Response &set(const QString &key, const QString &value) { header[key] = value; return *this; };

    quint16 status() const { return m_status; };
    Response &status(const quint16 &status) { m_status = status; return *this; };

    QString type() const { return header["content-type"]; };
    Response &type(const QString &type) { header["content-type"] = type; return *this; };

    QString body() const { return m_body;};
    Response &body(const QString &body) { m_body = body; return *this; };

    Response &write(const QString msg) { m_body += msg; return *this; };

    void send(const QString &body = "") {
        if (body.size())
            m_body = body;

        end();
    };

    void send(const QJsonDocument &body) {
        type("application/json");
        qDebug() << " body:" << body;
        m_body = body.toJson(QJsonDocument::Compact);

        end();
    }

    // final function set and called from recurse
    std::function<void()> end;

    QHash<QString, QString> header;
    QString method, protocol;
    QHash<quint16, QString> http_codes
    {
        {100, "Continue"},
        {101, "Switching Protocols"},
        {200, "OK"},
        {201, "Created"},
        {202, "Accepted"},
        {203, "Non-Authoritative Information"},
        {204, "No Content"},
        {205, "Reset Content"},
        {206, "Partial Content"},
        {300, "Multiple Choices"},
        {301, "Moved Permanently"},
        {302, "Found"},
        {303, "See Other"},
        {304, "Not Modified"},
        {305, "Use Proxy"},
        {307, "Temporary Redirect"},
        {400, "Bad Request"},
        {401, "Unauthorized"},
        {402, "Payment Required"},
        {403, "Forbidden"},
        {404, "Not Found"},
        {405, "Method Not Allowed"},
        {406, "Not Acceptable"},
        {407, "Proxy Authentication Required"},
        {408, "Request Time-out"},
        {409, "Conflict"},
        {410, "Gone"},
        {411, "Length Required"},
        {412, "Precondition Failed"},
        {413, "Request Entity Too Large"},
        {414, "Request-URI Too Large"},
        {415, "Unsupported Media Type"},
        {416, "Requested range not satisfiable"},
        {417, "Expectation Failed"},
        {500, "Internal Server Error"},
        {501, "Not Implemented"},
        {502, "Bad Gateway"},
        {503, "Service Unavailable"},
        {504, "Gateway Time-out"},
        {505, "HTTP Version not supported"}
    };

    //!
    //! \brief create_reply
    //! create reply for sending to client
    //!
    //! \return QString reply to be sent
    //!
    QString create_reply();

private:
    quint16 m_status = 200;
    QString m_body;
};

// https://tools.ietf.org/html/rfc7230#page-19
QString Response::create_reply()
{
    qDebug() << __FUNCTION__ << this->body();

    qDebug() << "response header:" << this->header;

    QString reply = this->protocol % " " % QString::number(this->status()) % " "
        % this->http_codes[this->status()] % "\r\n";

    // set content length
    this->header["content-length"] = QString::number(this->body().size());

    // set content type if not set
    if (!this->header.contains("content-type"))
        this->header["content-type"] = "text/plain";

    // set custom header fields
    for (auto i = this->header.constBegin(); i != this->header.constEnd(); ++i)
        reply = reply % i.key() % ": " % i.value() % "\r\n";

    reply += "\r\n";

    if (this->body().size())
        reply += this->body();

    return reply;
};

#endif
<commit_msg>response: minor pass by value/reference changes<commit_after>#ifndef RECURSE_RESPONSE_HPP
#define RECURSE_RESPONSE_HPP

#include <QHash>
#include <QJsonDocument>
#include <functional>

class Response {

public:

    QString get(const QString &key) { return header[key]; };
    Response &set(const QString &key, const QString &value) { header[key] = value; return *this; };

    quint16 status() const { return m_status; };
    Response &status(quint16 status) { m_status = status; return *this; };

    QString type() const { return header["content-type"]; };
    Response &type(const QString &type) { header["content-type"] = type; return *this; };

    QString body() const { return m_body;};
    Response &body(const QString &body) { m_body = body; return *this; };

    Response &write(const QString &msg) { m_body += msg; return *this; };

    void send(const QString &body = "") {
        if (body.size())
            m_body = body;

        end();
    };

    void send(const QJsonDocument &body) {
        type("application/json");
        qDebug() << " body:" << body;
        m_body = body.toJson(QJsonDocument::Compact);

        end();
    }

    // final function set and called from recurse
    std::function<void()> end;

    QHash<QString, QString> header;
    QString method, protocol;

    QHash<quint16, QString> http_codes
    {
        {100, "Continue"},
        {101, "Switching Protocols"},
        {200, "OK"},
        {201, "Created"},
        {202, "Accepted"},
        {203, "Non-Authoritative Information"},
        {204, "No Content"},
        {205, "Reset Content"},
        {206, "Partial Content"},
        {300, "Multiple Choices"},
        {301, "Moved Permanently"},
        {302, "Found"},
        {303, "See Other"},
        {304, "Not Modified"},
        {305, "Use Proxy"},
        {307, "Temporary Redirect"},
        {400, "Bad Request"},
        {401, "Unauthorized"},
        {402, "Payment Required"},
        {403, "Forbidden"},
        {404, "Not Found"},
        {405, "Method Not Allowed"},
        {406, "Not Acceptable"},
        {407, "Proxy Authentication Required"},
        {408, "Request Time-out"},
        {409, "Conflict"},
        {410, "Gone"},
        {411, "Length Required"},
        {412, "Precondition Failed"},
        {413, "Request Entity Too Large"},
        {414, "Request-URI Too Large"},
        {415, "Unsupported Media Type"},
        {416, "Requested range not satisfiable"},
        {417, "Expectation Failed"},
        {500, "Internal Server Error"},
        {501, "Not Implemented"},
        {502, "Bad Gateway"},
        {503, "Service Unavailable"},
        {504, "Gateway Time-out"},
        {505, "HTTP Version not supported"}
    };

    //!
    //! \brief create_reply
    //! create reply for sending to client
    //!
    //! \return QString reply to be sent
    //!
    QString create_reply();

private:
    quint16 m_status = 200;
    QString m_body;
};

// https://tools.ietf.org/html/rfc7230#page-19
QString Response::create_reply()
{
    qDebug() << __FUNCTION__ << this->body();

    qDebug() << "response header:" << this->header;

    QString reply = this->protocol % " " % QString::number(this->status()) % " "
        % this->http_codes[this->status()] % "\r\n";

    // set content length
    this->header["content-length"] = QString::number(this->body().size());

    // set content type if not set
    if (!this->header.contains("content-type"))
        this->header["content-type"] = "text/plain";

    // set custom header fields
    for (auto i = this->header.constBegin(); i != this->header.constEnd(); ++i)
        reply = reply % i.key() % ": " % i.value() % "\r\n";

    reply += "\r\n";

    if (this->body().size())
        reply += this->body();

    return reply;
};

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Cloudius Systems
 */

#include "core/reactor.hh"
#include "core/app-template.hh"
#include "core/temporary_buffer.hh"
#include "core/smp.hh"
#include <vector>
#include <iostream>

class http_server {
    std::vector<server_socket> _listeners;
public:
    future<> listen(ipv4_addr addr) {
        listen_options lo;
        lo.reuse_address = true;
        _listeners.push_back(engine.listen(make_ipv4_address(addr), lo));
        do_accepts(_listeners.size() - 1);
        return make_ready_future<>();
    }
    void do_accepts(int which) {
        _listeners[which].accept().then([this, which] (connected_socket fd, socket_address addr) mutable {
            auto conn = new connection(*this, std::move(fd), addr);
            conn->process().rescue([this, conn] (auto get_ex) {
                delete conn;
                try {
                    get_ex();
                } catch (std::exception& ex) {
                    std::cout << "request error " << ex.what() << "\n";
                }
            });
            do_accepts(which);
        }).rescue([] (auto get_ex) {
            try {
                get_ex();
            } catch (std::exception& ex) {
                std::cout << "accept failed: " << ex.what() << "\n";
            }
        });
    }
    class connection {
        connected_socket _fd;
        input_stream<char> _read_buf;
        output_stream<char> _write_buf;
    public:
        connection(http_server& server, connected_socket&& fd, socket_address addr)
            : _fd(std::move(fd))
            , _read_buf(_fd.input())
            , _write_buf(_fd.output()) {}
        future<> process() {
             return read();
        }
        future<> read() {
            if (_read_buf.eof()) {
                return make_ready_future();
            }
            // Expect a ping from client.
            size_t n = 4;
            return _read_buf.read_exactly(n).then([this] (temporary_buffer<char> buf) {
                if (buf.size() == 0) {
                    return make_ready_future();
                }
                return _write_buf.write("pong", 4).then([this] {
                    return _write_buf.flush();
                }).then([this] {
                    return this->read();
                });
            });
        }
    };
};

int main(int ac, char** av) {
    app_template app;
    app.add_options()
        ("port", bpo::value<uint16_t>()->default_value(10000), "TCP server port") ;
    return app.run(ac, av, [&] {
        auto&& config = app.configuration();
        uint16_t port = config["port"].as<uint16_t>();
        auto server = new distributed<http_server>;
        server->start().then([server = std::move(server), port] () mutable {
            server->invoke_on_all(&http_server::listen, ipv4_addr{port});
        }).then([port] {
            std::cout << "Seastar TCP server listening on port " << port << " ...\n";
        });
    });
}
<commit_msg>tests: Add send test to tcp_server<commit_after>/*
 * Copyright 2014 Cloudius Systems
 */

#include "core/reactor.hh"
#include "core/app-template.hh"
#include "core/temporary_buffer.hh"
#include "core/smp.hh"
#include <vector>
#include <iostream>

static std::string str_ping{"ping"};
static std::string str_txtx{"txtx"};
static std::string str_pong{"pong"};
static std::string str_unknow{"unknow cmd"};
static int tx_msg_total_size = 10 * 1024 * 1024;
static int tx_msg_size = 4 * 1024;
static int tx_msg_nr = tx_msg_total_size / tx_msg_size;
static std::string str_txbuf(tx_msg_size, 'X');

class http_server {
    std::vector<server_socket> _listeners;
public:
    future<> listen(ipv4_addr addr) {
        listen_options lo;
        lo.reuse_address = true;
        _listeners.push_back(engine.listen(make_ipv4_address(addr), lo));
        do_accepts(_listeners.size() - 1);
        return make_ready_future<>();
    }
    void do_accepts(int which) {
        _listeners[which].accept().then([this, which] (connected_socket fd, socket_address addr) mutable {
            auto conn = new connection(*this, std::move(fd), addr);
            conn->process().rescue([this, conn] (auto get_ex) {
                delete conn;
                try {
                    get_ex();
                } catch (std::exception& ex) {
                    std::cout << "request error " << ex.what() << "\n";
                }
            });
            do_accepts(which);
        }).rescue([] (auto get_ex) {
            try {
                get_ex();
            } catch (std::exception& ex) {
                std::cout << "accept failed: " << ex.what() << "\n";
            }
        });
    }
    class connection {
        connected_socket _fd;
        input_stream<char> _read_buf;
        output_stream<char> _write_buf;
    public:
        connection(http_server& server, connected_socket&& fd, socket_address addr)
            : _fd(std::move(fd))
            , _read_buf(_fd.input())
            , _write_buf(_fd.output()) {}
        future<> process() {
             return read();
        }
        future<> read() {
            if (_read_buf.eof()) {
                return make_ready_future();
            }
            // Expect 4 bytes cmd from client
            size_t n = 4;
            return _read_buf.read_exactly(n).then([this] (temporary_buffer<char> buf) {
                if (buf.size() == 0) {
                    return make_ready_future();
                }
                auto cmd = std::string(buf.get(), buf.size());
                // pingpong test
                if (cmd == str_ping) {
                    return _write_buf.write(str_pong).then([this] {
                        return _write_buf.flush();
                    }).then([this] {
                        return this->read();
                    });
                // server tx test
                } else if (cmd == str_txtx) {
                    return tx_test();
                // unknow test
                } else {
                    return _write_buf.write(str_unknow).then([this] {
                        return _write_buf.flush();
                    }).then([this] {
                        return make_ready_future();
                    });
                }
            });
        }
        future<> do_write(int end) {
            if (end == 0) {
                return make_ready_future<>();
            }
            return _write_buf.write(str_txbuf).then([this, end] {
                return _write_buf.flush();
            }).then([this, end] {
                return do_write(end - 1);
            });
        }
        future<> tx_test() {
            return do_write(tx_msg_nr).then([this] {
                return _write_buf.close();
            }).then([this] {
                return make_ready_future<>();
            });
        }
    };
};

int main(int ac, char** av) {
    app_template app;
    app.add_options()
        ("port", bpo::value<uint16_t>()->default_value(10000), "TCP server port") ;
    return app.run(ac, av, [&] {
        auto&& config = app.configuration();
        uint16_t port = config["port"].as<uint16_t>();
        auto server = new distributed<http_server>;
        server->start().then([server = std::move(server), port] () mutable {
            server->invoke_on_all(&http_server::listen, ipv4_addr{port});
        }).then([port] {
            std::cout << "Seastar TCP server listening on port " << port << " ...\n";
        });
    });
}
<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) FFLAS-FFPACK
 * Written by Clément Pernet <clement.pernet@imag.fr>
 * This file is Free Software and part of FFLAS-FFPACK.
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */

//--------------------------------------------------------------------------
//                        Test for ftrtri : 1 computation
//
//--------------------------------------------------------------------------
// Clement Pernet
//-------------------------------------------------------------------------

#define TIME 1

#include <iomanip>
#include <iostream>
#include "givaro/modular-balanced.h"

#include "fflas-ffpack/fflas-ffpack-config.h"

#include "fflas-ffpack/utils/timer.h"
#include "fflas-ffpack/utils/Matio.h"
#include "fflas-ffpack/ffpack/ffpack.h"

using namespace std;
using namespace FFPACK;

typedef Givaro::ModularBalanced<double> Field;

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

	size_t  n;
	int nbit=atoi(argv[3]); // number of times the product is performed
	cerr<<setprecision(10);

	if (argc != 4)	{
		cerr<<"Usage : test-ftrtri <p> <A> <<i>"
		    <<endl
		    <<"         to invert a triangular matrix  A mod p (i computations)"
		    <<endl;
		exit(-1);
	}
	Field F(atoi(argv[1]));
	Field::Element * A,*Ab;
	A = read_field(F,argv[2],&n,&n);
	Ab = FFLAS::fflas_new<Field::Element>(n*n);

	for (int i=0; i<n;++i){
		for(int j=i+1; j<n; ++j)
			F.assign(*(Ab+i*n+j),*(A+i*n+j));
		F.assign(*(Ab+i*(n+1)), 1.0);
		for(int j=0; j<i; ++j)
			F.assign(*(Ab+i*n+j),0.0);
	}

	Field::Element * X = FFLAS::fflas_new<Field::Element>(n*n);

 FFLAS::Timer tim,t; t.clear();tim.clear();

	for(int i = 0;i<nbit;++i){
		t.clear();
		t.start();
//				FFPACK::trinv_left (F, n, A, n, X, n);
				FFPACK::ftrtri(F, FFLAS::FflasUpper, FFLAS::FflasUnit, n, A, n);
		t.stop();
		tim+=t;
		if (i+1<nbit)
			for (int i=0; i<n*n;++i)
				F.assign(*(A+i),*(Ab+i));
	}

#ifdef __FFLASFFPACK_DEBUG
	FFLAS::ftrmm (F, FFLAS::FflasRight, FFLAS::FflasUpper, FFLAS::FflasNoTrans, FFLAS::FflasUnit,
		      n, n, 1.0,
		      A,n, Ab, n);
	bool wrong = false;

	for (int i=0;i<n;++i)
		for (int j=0;j<n;++j)
			if ( ((i!=j) && !F.isZero(*(Ab+i*n+j)))
			     ||((i==j) &&!F.isOne(*(Ab+i*n+j))))
				wrong = true;

	if ( wrong ){
		cerr<<"FAIL"<<endl;
		write_field (F,cerr<<"Ab="<<endl,Ab,n,n,n);
		    //write_field (F,cerr<<"X="<<endl,X,n,n,n);
	}else{

		cerr<<"PASS"<<endl;
	}
#endif

#if TIME
	double gflops = 1.0/3.0*(n/1000.0*n/1000000.0)*nbit*n/tim.usertime();
	cerr<<"n = "<<n<<" Inversion over Z/"<<atoi(argv[1])<<"Z : t= "
	     << tim.usertime()/nbit
	     << " s, Gfops = "<<gflops
	     << endl;

	cout<<n<<" "<<gflops<<" "<<tim.usertime()/nbit<<endl;
#endif
}
<commit_msg>modified test-ftrtri to comply to new standards<commit_after>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) FFLAS-FFPACK
 * Written by Clément Pernet <clement.pernet@imag.fr>
 * This file is Free Software and part of FFLAS-FFPACK.
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */

#define  __FFLASFFPACK_SEQUENTIAL

#define ENABLE_ALL_CHECKINGS 1

#include "fflas-ffpack/fflas-ffpack-config.h"

#include <iomanip>
#include <iostream>

#include "fflas-ffpack/utils/timer.h"
#include "fflas-ffpack/fflas/fflas.h"
#include "fflas-ffpack/utils/args-parser.h"
#include "test-utils.h"
#include <givaro/modular.h>

using namespace std;
using namespace FFPACK;
using namespace FFLAS;
using Givaro::Modular;
using Givaro::ModularBalanced;

template<typename Field, class RandIter>
bool check_ftrtri (const Field &F, size_t n, FFLAS_UPLO uplo, FFLAS_TRANSPOSE trans, FFLAS_DIAG diag, RandIter& Rand){
    typedef typename Field::Element Element;
    Element * A, * B;
    size_t lda = n + (rand() % n );
    A  = fflas_new(F,n,lda);
    B  = fflas_new(F,n,lda);

    RandomTriangularMatrix (F, n, n, uplo, diag, true, A, lda, Rand);
    fassign (F, n, n, A, lda, B, lda);

    string ss=string((uplo == FflasLower)?"Lower_":"Upper_")+string((trans == FflasTrans)?"Trans_":"NoTrans_")+string((diag == FflasUnit)?"Unit":"NonUnit");

    cout<<std::left<<"Checking FTRTRI_";
    cout.fill('.');
    cout.width(30);
    cout<<ss;

    Timer t; t.clear();
    double time=0.0;
    t.clear();
    t.start();
    ftrtri (F, uplo, diag, n, A, lda);
    t.stop();
    time+=t.usertime();

    // B <- A times B
    ftrmm(F, FFLAS::FflasLeft, uplo, trans, diag, n, n, F.one, A, lda, B, lda);

    // Is B the identity matrix ?
    bool ok = true;
    for(size_t li = 0; li < n && ok; li++){
	    for(size_t co = 0; co < n && ok; co++){
		    ok = ((li == co) && (F.areEqual(A[li*(lda+1)],F.one))) || (F.areEqual(A[li*lda+co],F.zero));
	    }
    }

    if (ok){
	    cout << "PASSED ("<<time<<")"<<endl;
    } else{
	    cout << "FAILED ("<<time<<")"<<endl;
    }

    fflas_delete(A);
    fflas_delete(B);
    return ok;
}
template <class Field>
bool run_with_field (Givaro::Integer q, size_t b, size_t n, size_t iters, uint64_t seed){
    bool ok = true ;
    int nbit=(int)iters;

    while (ok &&  nbit){
	    //typedef typename Field::Element Element ;
	    // choose Field
	    Field* F= chooseField<Field>(q,b);
	    typename Field::RandIter G(*F,0,seed);
	    if (F==nullptr)
		    return true;

	    cout<<"Checking with ";F->write(cout)<<endl;

	    ok = ok && check_ftrtri(*F,n,FflasLower,FflasNoTrans,FflasUnit,G);
	    ok = ok && check_ftrtri(*F,n,FflasUpper,FflasNoTrans,FflasUnit,G);
	    ok = ok && check_ftrtri(*F,n,FflasLower,FflasTrans,FflasUnit,G);
	    ok = ok && check_ftrtri(*F,n,FflasUpper,FflasTrans,FflasUnit,G);
	    ok = ok && check_ftrtri(*F,n,FflasLower,FflasNoTrans,FflasNonUnit,G);
	    ok = ok && check_ftrtri(*F,n,FflasUpper,FflasNoTrans,FflasNonUnit,G);
	    ok = ok && check_ftrtri(*F,n,FflasLower,FflasTrans,FflasNonUnit,G);
	    ok = ok && check_ftrtri(*F,n,FflasUpper,FflasTrans,FflasNonUnit,G);
	    nbit--;
	    delete F;
    }
    return ok;
}

int main(int argc, char** argv)
{
    cerr<<setprecision(10);
    Givaro::Integer q=-1;
    size_t b=0;
    size_t n=483;
    size_t iters=1;
    bool loop=false;
    uint64_t seed = time(NULL);
    Argument as[] = {
	    { 'q', "-q Q", "Set the field characteristic (-1 for random).",         TYPE_INTEGER , &q },
	    { 'b', "-b B", "Set the bitsize of the field characteristic.",  TYPE_INT , &b },
	    { 'n', "-n N", "Set the dimension of the system.", TYPE_INT , &n },
	    { 'i', "-i R", "Set number of repetitions.",            TYPE_INT , &iters },
	    { 'l', "-loop Y/N", "run the test in an infinite loop.", TYPE_BOOL , &loop },
	    { 's', "-s seed", "Set seed for the random generator", TYPE_INT, &seed },
	    END_OF_ARGUMENTS
    };

    parseArguments(argc,argv,as);

    bool ok = true;
    do{
	    ok &= run_with_field<Modular<double> >(q,b,n,iters,seed);
	    ok &= run_with_field<ModularBalanced<double> >(q,b,n,iters,seed);
	    ok &= run_with_field<Modular<float> >(q,b,n,iters,seed);
	    ok &= run_with_field<ModularBalanced<float> >(q,b,n,iters,seed);
	    ok &= run_with_field<Modular<int32_t> >(q,b,n,iters,seed);
	    ok &= run_with_field<ModularBalanced<int32_t> >(q,b,n,iters,seed);
	    ok &= run_with_field<Modular<int64_t> >(q,b,n,iters,seed);
	    ok &= run_with_field<ModularBalanced<int64_t> >(q,b,n,iters,seed);
	    ok &= run_with_field<Modular<Givaro::Integer> >(q,5,n/4+1,iters,seed);
	    ok &= run_with_field<Modular<Givaro::Integer> >(q,(b?b:512),n/4+1,iters,seed);
    } while (loop && ok);

    return !ok ;
}
<|endoftext|>