<commit_before>#include <silicium/config.hpp>
#include <silicium/bounded_int.hpp>
#include <silicium/variant.hpp>
#include <silicium/array_view.hpp>
#include <silicium/arithmetic/add.hpp>
#include <boost/test/unit_test.hpp>

namespace Si
{
	namespace m3
	{
		template <class T>
		void trivial_copy(T &destination, T const &source)
		{
			std::memcpy(&destination, &source, sizeof(source));
		}

		template <class T>
		struct val
		{
			template <class... Args>
			explicit val(Args &&... args)
			    : m_is_set(true)
			{
				new (static_cast<void *>(&get())) T(std::forward<Args>(args)...);
			}

			~val() BOOST_NOEXCEPT
			{
				if (!m_is_set)
				{
					return;
				}
				get().~T();
			}

			val(val &&other) BOOST_NOEXCEPT : m_is_set(other.m_is_set)
			{
				if (m_is_set)
				{
					trivial_copy(get(), other.get());
					other.m_is_set = false;
				}
			}

			val &operator=(val &&other) BOOST_NOEXCEPT
			{
				if (m_is_set)
				{
					if (other.m_is_set)
					{
						get().~T();
						trivial_copy(get(), other.get());
						other.m_is_set = false;
					}
					else
					{
						get().~T();
						m_is_set = false;
					}
				}
				else
				{
					if (other.m_is_set)
					{
						trivial_copy(get(), other.get());
						other.m_is_set = false;
						m_is_set = true;
					}
					else
					{
						// nothing to do
					}
				}
				return *this;
			}

			void release() BOOST_NOEXCEPT
			{
				m_is_set = false;
			}

			T &require()
			{
				if (!m_is_set)
				{
					boost::throw_exception(std::logic_error("expected non-empty val"));
				}
				return get();
			}

			void transfer(T &destination) BOOST_NOEXCEPT
			{
				trivial_copy(destination, require());
				release();
			}

		private:
			bool m_is_set;
			typename std::aligned_storage<sizeof(T), alignof(T)>::type m_storage;

			T &get()
			{
				return reinterpret_cast<T &>(reinterpret_cast<char &>(m_storage));
			}
		};

		template <class T, class Deleter>
		struct unique_ref : private Deleter
		{
			explicit unique_ref(T &ref, Deleter deleter) BOOST_NOEXCEPT : Deleter(deleter), m_ptr(&ref)
			{
			}

			explicit unique_ref(val<unique_ref> other) BOOST_NOEXCEPT
			{
				other.transfer(*this);
			}

			~unique_ref() BOOST_NOEXCEPT
			{
				Deleter::operator()(*m_ptr);
			}

			SILICIUM_DISABLE_COPY(unique_ref)

			T &ref() const BOOST_NOEXCEPT
			{
				return *m_ptr;
			}

		private:
			T *m_ptr;
		};

		struct new_deleter
		{
			new_deleter() BOOST_NOEXCEPT
			{
			}

			template <class T>
			void operator()(T &deleted) const BOOST_NOEXCEPT
			{
				delete &deleted;
			}
		};

		struct malloc_deleter
		{
			malloc_deleter() BOOST_NOEXCEPT
			{
			}

			template <class T>
			void operator()(T &deleted) const BOOST_NOEXCEPT
			{
				std::free(&deleted);
			}
		};

		template <class T, class... Args>
		val<unique_ref<T, new_deleter>> make_unique(Args &&... args)
		{
			return val<unique_ref<T, new_deleter>>(*new T(std::forward<Args>(args)...), new_deleter());
		}

		template <class T>
		val<unique_ref<T, malloc_deleter>> allocate_array_storage(std::size_t length)
		{
			void *const storage = std::calloc(length, sizeof(T));
			if (!storage)
			{
				boost::throw_exception(std::bad_alloc());
			}
			return val<unique_ref<T, malloc_deleter>>(*static_cast<T *>(storage), malloc_deleter());
		}

		template <class T, class Length>
		struct dynamic_array : private Length
		{
			template <class ElementGenerator>
			dynamic_array(Length length, ElementGenerator &&generate_elements) BOOST_NOEXCEPT
			    : Length(length),
			      m_elements(allocate_array_storage<T>(length.value()))
			{
				for (typename Length::value_type i = 0, c = this->length().value(); i < c; ++i)
				{
					generate_elements().transfer((&m_elements.ref())[i]);
				}
			}

			~dynamic_array() BOOST_NOEXCEPT
			{
				for (typename Length::value_type i = 0, c = length().value(); i < c; ++i)
				{
					(&m_elements.ref())[c - i - 1].~T();
				}
			}

			Length length() const BOOST_NOEXCEPT
			{
				return *this;
			}

			array_view<T, Length> as_view() const BOOST_NOEXCEPT
			{
				return array_view<T, Length>(m_elements.ref(), length());
			}

			SILICIUM_DISABLE_COPY(dynamic_array)

		private:
			unique_ref<T, malloc_deleter> m_elements;
		};
	}
}

BOOST_AUTO_TEST_CASE(move3_val)
{
	Si::m3::val<Si::m3::unique_ref<int, Si::m3::new_deleter>> r = Si::m3::make_unique<int>(23);
	BOOST_CHECK_EQUAL(23, r.require().ref());
	Si::m3::val<Si::m3::unique_ref<int, Si::m3::new_deleter>> s = std::move(r);
	BOOST_CHECK_EQUAL(23, s.require().ref());
	s.require().ref() = 24;
	r = std::move(s);
	BOOST_CHECK_EQUAL(24, r.require().ref());
	Si::m3::unique_ref<int, Si::m3::new_deleter> t(std::move(r));
	BOOST_CHECK_EQUAL(24, t.ref());
}

BOOST_AUTO_TEST_CASE(move3_vector_ref_emplace_back)
{
	typedef Si::bounded_int<std::size_t, 1, 2> length_type;
	Si::m3::dynamic_array<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type> const v(
	    length_type::literal<1>(), []()
	    {
		    return Si::m3::make_unique<int>(23);
		});
	BOOST_REQUIRE_EQUAL(length_type::literal<1>(), v.length());
	Si::array_view<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type> const range = v.as_view();
	BOOST_REQUIRE_EQUAL(length_type::literal<1>(), range.length());
	Si::m3::unique_ref<int, Si::m3::new_deleter> const &element = range[Si::literal<std::size_t, 0>()];
	BOOST_CHECK_EQUAL(element.ref(), 23);
}
<commit_msg>make dynamic_array movable<commit_after>#include <silicium/config.hpp>
#include <silicium/bounded_int.hpp>
#include <silicium/variant.hpp>
#include <silicium/array_view.hpp>
#include <silicium/arithmetic/add.hpp>
#include <boost/test/unit_test.hpp>

namespace Si
{
	namespace m3
	{
		template <class T>
		void trivial_copy(T &destination, T const &source)
		{
			std::memcpy(&destination, &source, sizeof(source));
		}

		template <class T>
		struct val
		{
			val() BOOST_NOEXCEPT : m_is_set(false)
			{
			}

			template <class... Args>
			explicit val(Args &&... args)
			    : m_is_set(true)
			{
				new (static_cast<void *>(&get())) T(std::forward<Args>(args)...);
			}

			~val() BOOST_NOEXCEPT
			{
				if (!m_is_set)
				{
					return;
				}
				get().~T();
			}

			val(val &&other) BOOST_NOEXCEPT : m_is_set(other.m_is_set)
			{
				if (m_is_set)
				{
					trivial_copy(get(), other.get());
					other.m_is_set = false;
				}
			}

			val &operator=(val &&other) BOOST_NOEXCEPT
			{
				if (m_is_set)
				{
					if (other.m_is_set)
					{
						get().~T();
						trivial_copy(get(), other.get());
						other.m_is_set = false;
					}
					else
					{
						get().~T();
						m_is_set = false;
					}
				}
				else
				{
					if (other.m_is_set)
					{
						trivial_copy(get(), other.get());
						other.m_is_set = false;
						m_is_set = true;
					}
					else
					{
						// nothing to do
					}
				}
				return *this;
			}

			void release() BOOST_NOEXCEPT
			{
				m_is_set = false;
			}

			T &require()
			{
				if (!m_is_set)
				{
					boost::throw_exception(std::logic_error("expected non-empty val"));
				}
				return get();
			}

			void transfer(T &destination) BOOST_NOEXCEPT
			{
				trivial_copy(destination, require());
				release();
			}

			static val steal(T &from)
			{
				val result;
				trivial_copy(result.get(), from);
				result.m_is_set = true;
				return result;
			}

		private:
			bool m_is_set;
			typename std::aligned_storage<sizeof(T), alignof(T)>::type m_storage;

			T &get()
			{
				return reinterpret_cast<T &>(reinterpret_cast<char &>(m_storage));
			}
		};

		template <class T>
		val<T> steal(T &stolen)
		{
			return val<T>::steal(stolen);
		}

		template <class T, class Deleter>
		struct unique_ref : private Deleter
		{
			explicit unique_ref(T &ref, Deleter deleter) BOOST_NOEXCEPT : Deleter(deleter), m_ptr(&ref)
			{
			}

			explicit unique_ref(val<unique_ref> other) BOOST_NOEXCEPT
			{
				other.transfer(*this);
			}

			~unique_ref() BOOST_NOEXCEPT
			{
				Deleter::operator()(*m_ptr);
			}

			SILICIUM_DISABLE_COPY(unique_ref)

			T &ref() const BOOST_NOEXCEPT
			{
				return *m_ptr;
			}

		private:
			T *m_ptr;
		};

		struct new_deleter
		{
			new_deleter() BOOST_NOEXCEPT
			{
			}

			template <class T>
			void operator()(T &deleted) const BOOST_NOEXCEPT
			{
				delete &deleted;
			}
		};

		struct malloc_deleter
		{
			malloc_deleter() BOOST_NOEXCEPT
			{
			}

			template <class T>
			void operator()(T &deleted) const BOOST_NOEXCEPT
			{
				std::free(&deleted);
			}
		};

		template <class T, class... Args>
		val<unique_ref<T, new_deleter>> make_unique(Args &&... args)
		{
			return val<unique_ref<T, new_deleter>>(*new T(std::forward<Args>(args)...), new_deleter());
		}

		template <class T>
		val<unique_ref<T, malloc_deleter>> allocate_array_storage(std::size_t length)
		{
			void *const storage = std::calloc(length, sizeof(T));
			if (!storage)
			{
				boost::throw_exception(std::bad_alloc());
			}
			return val<unique_ref<T, malloc_deleter>>(*static_cast<T *>(storage), malloc_deleter());
		}

		template <class T, class Length>
		struct dynamic_array : private Length
		{
			template <class ElementGenerator>
			dynamic_array(Length length, ElementGenerator &&generate_elements) BOOST_NOEXCEPT
			    : Length(length),
			      m_elements(allocate_array_storage<T>(length.value()))
			{
				for (typename Length::value_type i = 0, c = this->length().value(); i < c; ++i)
				{
					generate_elements().transfer((&m_elements.ref())[i]);
				}
			}

			explicit dynamic_array(val<dynamic_array> other) BOOST_NOEXCEPT
			    : Length(other.require()),
			      m_elements(steal(other.require().m_elements))
			{
				other.release();
			}

			~dynamic_array() BOOST_NOEXCEPT
			{
				for (typename Length::value_type i = 0, c = length().value(); i < c; ++i)
				{
					(&m_elements.ref())[c - i - 1].~T();
				}
			}

			Length length() const BOOST_NOEXCEPT
			{
				return *this;
			}

			array_view<T, Length> as_view() const BOOST_NOEXCEPT
			{
				return array_view<T, Length>(m_elements.ref(), length());
			}

			SILICIUM_DISABLE_COPY(dynamic_array)

		private:
			unique_ref<T, malloc_deleter> m_elements;
		};
	}
}

BOOST_AUTO_TEST_CASE(move3_val)
{
	Si::m3::val<Si::m3::unique_ref<int, Si::m3::new_deleter>> r = Si::m3::make_unique<int>(23);
	BOOST_CHECK_EQUAL(23, r.require().ref());
	Si::m3::val<Si::m3::unique_ref<int, Si::m3::new_deleter>> s = std::move(r);
	BOOST_CHECK_EQUAL(23, s.require().ref());
	s.require().ref() = 24;
	r = std::move(s);
	BOOST_CHECK_EQUAL(24, r.require().ref());
	Si::m3::unique_ref<int, Si::m3::new_deleter> t(std::move(r));
	BOOST_CHECK_EQUAL(24, t.ref());
}

BOOST_AUTO_TEST_CASE(move3_vector_ref_emplace_back)
{
	typedef Si::bounded_int<std::size_t, 1, 2> length_type;
	Si::m3::dynamic_array<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type> const v(
	    length_type::literal<1>(), []()
	    {
		    return Si::m3::make_unique<int>(23);
		});
	BOOST_REQUIRE_EQUAL(length_type::literal<1>(), v.length());
	Si::array_view<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type> const range = v.as_view();
	BOOST_REQUIRE_EQUAL(length_type::literal<1>(), range.length());
	Si::m3::unique_ref<int, Si::m3::new_deleter> const &element = range[Si::literal<std::size_t, 0>()];
	BOOST_CHECK_EQUAL(element.ref(), 23);
}

BOOST_AUTO_TEST_CASE(move3_val_of_vector)
{
	typedef Si::bounded_int<std::size_t, 1, 2> length_type;
	auto create_array = []()
	{
		return Si::m3::val<Si::m3::dynamic_array<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type>>(
		    length_type::literal<1>(), []()
		    {
			    return Si::m3::make_unique<int>(23);
			});
	};
	Si::m3::val<Si::m3::dynamic_array<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type>> a = create_array();
	Si::m3::dynamic_array<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type> const v(std::move(a));
	BOOST_REQUIRE_EQUAL(length_type::literal<1>(), v.length());
	Si::array_view<Si::m3::unique_ref<int, Si::m3::new_deleter>, length_type> const range = v.as_view();
	BOOST_REQUIRE_EQUAL(length_type::literal<1>(), range.length());
	Si::m3::unique_ref<int, Si::m3::new_deleter> const &element = range[Si::literal<std::size_t, 0>()];
	BOOST_CHECK_EQUAL(element.ref(), 23);
}
<|endoftext|>


<commit_before>/**

Algorithm Info:
https://131002.net/siphash/

Based off of implementation:
https://github.com/floodyberry/siphash

 */

#include "ts/HashSip.h"
#include <cstring>

using namespace std;

#define SIP_BLOCK_SIZE 8

#define ROTL64(a, b) (((a) << (b)) | ((a) >> (64 - b)))

#define U8TO64_LE(p) *(const uint64_t *)(p)

#define SIPCOMPRESS(x0, x1, x2, x3) \
  x0 += x1;                         \
  x2 += x3;                         \
  x1 = ROTL64(x1, 13);              \
  x3 = ROTL64(x3, 16);              \
  x1 ^= x0;                         \
  x3 ^= x2;                         \
  x0 = ROTL64(x0, 32);              \
  x2 += x1;                         \
  x0 += x3;                         \
  x1 = ROTL64(x1, 17);              \
  x3 = ROTL64(x3, 21);              \
  x1 ^= x2;                         \
  x3 ^= x0;                         \
  x2 = ROTL64(x2, 32);

ATSHash64Sip24::ATSHash64Sip24()
{
  this->clear();
}

ATSHash64Sip24::ATSHash64Sip24(const unsigned char key[16]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof(k0)))
{
  this->clear();
}

ATSHash64Sip24::ATSHash64Sip24(uint64_t key0, uint64_t key1)
{
  this->clear();
}

void
ATSHash64Sip24::update(const void *data, size_t len)
{
  size_t i, blocks;
  unsigned char *m;
  uint64_t mi;
  uint8_t block_off = 0;

  if (!finalized) {
    m = (unsigned char *)data;
    total_len += len;

    if (len + block_buffer_len < SIP_BLOCK_SIZE) {
      memcpy(block_buffer + block_buffer_len, m, len);
      block_buffer_len += len;
    } else {
      if (block_buffer_len > 0) {
        block_off = SIP_BLOCK_SIZE - block_buffer_len;
        memcpy(block_buffer + block_buffer_len, m, block_off);

        mi = U8TO64_LE(block_buffer);
        v3 ^= mi;
        SIPCOMPRESS(v0, v1, v2, v3);
        SIPCOMPRESS(v0, v1, v2, v3);
        v0 ^= mi;
      }

      for (i = block_off, blocks = ((len - block_off) & ~(SIP_BLOCK_SIZE - 1)); i < blocks; i += SIP_BLOCK_SIZE) {
        mi = U8TO64_LE(m + i);
        v3 ^= mi;
        SIPCOMPRESS(v0, v1, v2, v3);
        SIPCOMPRESS(v0, v1, v2, v3);
        v0 ^= mi;
      }

      block_buffer_len = (len - block_off) & (SIP_BLOCK_SIZE - 1);
      memcpy(block_buffer, m + block_off + blocks, block_buffer_len);
    }
  }
}

void
ATSHash64Sip24::final()
{
  uint64_t last7;
  int i;

  if (!finalized) {
    last7 = (uint64_t)(total_len & 0xff) << 56;

    for (i = block_buffer_len - 1; i >= 0; i--) {
      last7 |= (uint64_t)block_buffer[i] << (i * 8);
    }

    v3 ^= last7;
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    v0 ^= last7;
    v2 ^= 0xff;
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    hfinal    = v0 ^ v1 ^ v2 ^ v3;
    finalized = true;
  }
}

uint64_t
ATSHash64Sip24::get() const
{
  if (finalized) {
    return hfinal;
  } else {
    return 0;
  }
}

void
ATSHash64Sip24::clear()
{
  v0               = k0 ^ 0x736f6d6570736575ull;
  v1               = k1 ^ 0x646f72616e646f6dull;
  v2               = k0 ^ 0x6c7967656e657261ull;
  v3               = k1 ^ 0x7465646279746573ull;
  finalized        = false;
  total_len        = 0;
  block_buffer_len = 0;
}
<commit_msg>Add initializer list for constructor<commit_after>/**

Algorithm Info:
https://131002.net/siphash/

Based off of implementation:
https://github.com/floodyberry/siphash

 */

#include "ts/HashSip.h"
#include <cstring>

using namespace std;

#define SIP_BLOCK_SIZE 8

#define ROTL64(a, b) (((a) << (b)) | ((a) >> (64 - b)))

#define U8TO64_LE(p) *(const uint64_t *)(p)

#define SIPCOMPRESS(x0, x1, x2, x3) \
  x0 += x1;                         \
  x2 += x3;                         \
  x1 = ROTL64(x1, 13);              \
  x3 = ROTL64(x3, 16);              \
  x1 ^= x0;                         \
  x3 ^= x2;                         \
  x0 = ROTL64(x0, 32);              \
  x2 += x1;                         \
  x0 += x3;                         \
  x1 = ROTL64(x1, 17);              \
  x3 = ROTL64(x3, 21);              \
  x1 ^= x2;                         \
  x3 ^= x0;                         \
  x2 = ROTL64(x2, 32);

ATSHash64Sip24::ATSHash64Sip24()
{
  this->clear();
}

ATSHash64Sip24::ATSHash64Sip24(const unsigned char key[16]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof(k0)))
{
  this->clear();
}

ATSHash64Sip24::ATSHash64Sip24(uint64_t key0, uint64_t key1) : k0(key0), k1(key1)
{
  this->clear();
}

void
ATSHash64Sip24::update(const void *data, size_t len)
{
  size_t i, blocks;
  unsigned char *m;
  uint64_t mi;
  uint8_t block_off = 0;

  if (!finalized) {
    m = (unsigned char *)data;
    total_len += len;

    if (len + block_buffer_len < SIP_BLOCK_SIZE) {
      memcpy(block_buffer + block_buffer_len, m, len);
      block_buffer_len += len;
    } else {
      if (block_buffer_len > 0) {
        block_off = SIP_BLOCK_SIZE - block_buffer_len;
        memcpy(block_buffer + block_buffer_len, m, block_off);

        mi = U8TO64_LE(block_buffer);
        v3 ^= mi;
        SIPCOMPRESS(v0, v1, v2, v3);
        SIPCOMPRESS(v0, v1, v2, v3);
        v0 ^= mi;
      }

      for (i = block_off, blocks = ((len - block_off) & ~(SIP_BLOCK_SIZE - 1)); i < blocks; i += SIP_BLOCK_SIZE) {
        mi = U8TO64_LE(m + i);
        v3 ^= mi;
        SIPCOMPRESS(v0, v1, v2, v3);
        SIPCOMPRESS(v0, v1, v2, v3);
        v0 ^= mi;
      }

      block_buffer_len = (len - block_off) & (SIP_BLOCK_SIZE - 1);
      memcpy(block_buffer, m + block_off + blocks, block_buffer_len);
    }
  }
}

void
ATSHash64Sip24::final()
{
  uint64_t last7;
  int i;

  if (!finalized) {
    last7 = (uint64_t)(total_len & 0xff) << 56;

    for (i = block_buffer_len - 1; i >= 0; i--) {
      last7 |= (uint64_t)block_buffer[i] << (i * 8);
    }

    v3 ^= last7;
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    v0 ^= last7;
    v2 ^= 0xff;
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    SIPCOMPRESS(v0, v1, v2, v3);
    hfinal    = v0 ^ v1 ^ v2 ^ v3;
    finalized = true;
  }
}

uint64_t
ATSHash64Sip24::get() const
{
  if (finalized) {
    return hfinal;
  } else {
    return 0;
  }
}

void
ATSHash64Sip24::clear()
{
  v0               = k0 ^ 0x736f6d6570736575ull;
  v1               = k1 ^ 0x646f72616e646f6dull;
  v2               = k0 ^ 0x6c7967656e657261ull;
  v3               = k1 ^ 0x7465646279746573ull;
  finalized        = false;
  total_len        = 0;
  block_buffer_len = 0;
}
<|endoftext|>


<commit_before>/**
 *  \file   stuff.hh
 *  \brief  contains some stuff
 **/
#ifndef STUFF_MISC_HH_INCLUDED
#define STUFF_MISC_HH_INCLUDED

#define SEGFAULT {int*J=0;*J=9;}

template <typename T>
bool isnan( T x ) { return !(x==x); }

#ifndef NDEBUG
    #ifndef LOGIC_ERROR
        #include <stdexcept>
        #include <sstream>
        #define LOGIC_ERROR \
            {\
                std::stringstream ss; ss << __FILE__ << ":" << __LINE__ << " should never be called"; \
                throw std::logic_error(ss.str());\
            }
    #endif
#else
    #define LOGIC_ERROR
#endif

#include <fstream>
#include <ostream>
#include <sstream>
#include <vector>
#include <assert.h>
#include <cmath>

namespace Stuff
{

/**
 *  \todo doc me
 **/
template < class ReturnType >
ReturnType fromString(const std::string& s)
{
    std::stringstream ss;
    ss << s;
    ReturnType r;
    ss >> r;
    return r;
}

/**
 *  \todo doc
 **/
template < class ReturnType >
std::string toString(const ReturnType& s)
{
    std::stringstream ss;
    ss << s;
    std::string r;
    ss >> r;
    return r;
}

template < class Info >
class TexOutput
{
    typedef std::vector< std::string >
        Strings;

    Info info_;
    double current_h_;
    Strings headers_;

    public:
        TexOutput( const Info& info, Strings& headers )
            : info_(info),
            current_h_(1.0),
            headers_(headers)
        {}

        TexOutput( Strings& headers )
            : info_(Info()),
            current_h_(1.0),
            headers_(headers)
        {}

        void setInfo( const Info& info )
        {
            info_ = info;
        }

        void putLineEnd( std::ofstream& outputFile_ )
        {
            outputFile_ << "\n"
                << "\\tabularnewline\n"
	              << "\\hline \n";
            outputFile_.flush();
        }

        void putErrorCol( std::ofstream& outputFile_, const double prevError_, const double error_, const double prevh_,  const bool /*initial*/  )
        {
            current_h_ = info_.grid_width;
            double factor = current_h_/prevh_;
            double eoc = std::log(error_/prevError_)/std::log(factor);
            outputFile_ << " & " << error_ << " & " << eoc;
        }

        void putHeader( std::ofstream& outputFile_ )
        {
            const unsigned int dynColSize = 2;
            const unsigned int statColSize = headers_.size() - 2;
            outputFile_ << "\\begin{longtable}{";
            for (unsigned int i=0;i<statColSize;i++) {
                if ( i == 2 )
                    outputFile_ << "|r|";//runtime col
                else
                    outputFile_ << "|c|";
            }

            for (unsigned int i=0;i<dynColSize;i++) {
                outputFile_ << "|cc|";
            }
            outputFile_ << "}\n"
                << "\\caption{"
                << " Grid: " << info_.gridname
                << " BFG: " << ( info_.bfg ? std::string("yes") : std::string("no") )
                << " Polorder (u,p,$\\sigma$): (" << info_.polorder_velocity << ", "<< info_.polorder_pressure << ", "<< info_.polorder_sigma << " ) "
                << "}\\\\  \n"
                << "\\hline \n";

            for (unsigned int i=0;i<statColSize;i++) {
                outputFile_ << headers_[i];
                if ( i <  statColSize - 1 )
                    outputFile_ << " & ";
            }
            for (unsigned int i=0;i<dynColSize;i++) {
                outputFile_ << " & " << headers_[i+statColSize]
                    << " & EOC ";
            }
            outputFile_ << "\n \\endhead\n"
                        << "\\hline\n"
                        << "\\hline\n";
        }

        void putStaticCols( std::ofstream& outputFile_ )
        {
            std::stringstream runtime;
            if ( info_.run_time > 59 )
                runtime << long(info_.run_time) / 60 << ":" << long(info_.run_time) % 60 ;
            else
                runtime << long(info_.run_time) ;

            outputFile_ << std::setw( 4 )
                << info_.grid_width << " & "
                << info_.codim0 << " & "
                << runtime.str() << " & "
                << info_.c11 << " & "
                << info_.d11 << " & "
                << info_.c12 << " & "
                << info_.d12 ;

        }

        void endTable( std::ofstream& outputFile_ )
        {
            outputFile_ << "\\end{longtable}";
            outputFile_.flush();
        }

        double get_h ()
        {
            return current_h_;
        }
};

/**
 *  \brief Only free mem pointed to by valid pointer, log warning otherwise
 *
 **/

template < class T >
void safe_delete ( T t ) //this is actually bullshit :P
{
    if (t){
        delete t;
        t=0;
    }
    //else log warning
}

template < class Container, class Element >
int getIdx( const Container& ct, Element e )
{
    int idx = 0;
    for ( typename Container::const_iterator it = ct.begin(); it != ct.end(); ++it, ++idx )
    {
        if ( *it == e )
            return idx;
    }
    return -1;
}

//! strip filename from \path if present, return empty string if only filename present
std::string pathOnly ( std::string path )
{
    if (!path.empty())
    {
        char buf[1024];//not _exactly_ sure this is max path length, but it's suggested in wx source

        // Local copy
        strcpy (buf, path.c_str() );

        int l = path.length();
        int i = l - 1;

        // Search backward for a backward or forward slash
        while (i > -1)
        {
            if ( ( path[i] == '/' ) || ( path[i] == '\\' ) )
            {
                // Don't return an empty string
                if (i == 0)
                    i ++;
                buf[i] = 0;
                return std::string(buf);
            }
            i --;
        }
    }
    return std::string();
}

//! may include filename, will be stripped
bool testCreateDirectory( std::string path ) {
    std::string pathonly = pathOnly(path);
    if ( pathonly.empty() )
        return true; //no dir to create

    //maybe test if dir exists??
    bool ok = ( mkdir(pathonly.c_str(), 0755 ) == 0 );
    if ( !ok ) {
        perror( pathonly.c_str() );
        return errno == EEXIST;
    }
    return true;
}

} // end namepspace stuff

#endif // end of stuff.hh
<commit_msg>more info in table caption<commit_after>/**
 *  \file   stuff.hh
 *  \brief  contains some stuff
 **/
#ifndef STUFF_MISC_HH_INCLUDED
#define STUFF_MISC_HH_INCLUDED

#define SEGFAULT {int*J=0;*J=9;}

template <typename T>
bool isnan( T x ) { return !(x==x); }

#ifndef NDEBUG
    #ifndef LOGIC_ERROR
        #include <stdexcept>
        #include <sstream>
        #define LOGIC_ERROR \
            {\
                std::stringstream ss; ss << __FILE__ << ":" << __LINE__ << " should never be called"; \
                throw std::logic_error(ss.str());\
            }
    #endif
#else
    #define LOGIC_ERROR
#endif

#include <fstream>
#include <ostream>
#include <sstream>
#include <vector>
#include <assert.h>
#include <cmath>

namespace Stuff
{

/**
 *  \todo doc me
 **/
template < class ReturnType >
ReturnType fromString(const std::string& s)
{
    std::stringstream ss;
    ss << s;
    ReturnType r;
    ss >> r;
    return r;
}

/**
 *  \todo doc
 **/
template < class ReturnType >
std::string toString(const ReturnType& s)
{
    std::stringstream ss;
    ss << s;
    std::string r;
    ss >> r;
    return r;
}

template < class Info >
class TexOutput
{
    typedef std::vector< std::string >
        Strings;

    Info info_;
    double current_h_;
    Strings headers_;

    public:
        TexOutput( const Info& info, Strings& headers )
            : info_(info),
            current_h_(1.0),
            headers_(headers)
        {}

        TexOutput( Strings& headers )
            : info_(Info()),
            current_h_(1.0),
            headers_(headers)
        {}

        void setInfo( const Info& info )
        {
            info_ = info;
        }

        void putLineEnd( std::ofstream& outputFile_ )
        {
            outputFile_ << "\n"
                << "\\tabularnewline\n"
	              << "\\hline \n";
            outputFile_.flush();
        }

        void putErrorCol( std::ofstream& outputFile_, const double prevError_, const double error_, const double prevh_,  const bool /*initial*/  )
        {
            current_h_ = info_.grid_width;
            double factor = current_h_/prevh_;
            double eoc = std::log(error_/prevError_)/std::log(factor);
            outputFile_ << " & " << error_ << " & " << eoc;
        }

        void putHeader( std::ofstream& outputFile_ )
        {
            const unsigned int dynColSize = 2;
            const unsigned int statColSize = headers_.size() - 2;
            outputFile_ << "\\begin{longtable}{";
            for (unsigned int i=0;i<statColSize;i++) {
                if ( i == 2 )
                    outputFile_ << "|r|";//runtime col
                else
                    outputFile_ << "|c|";
            }

            for (unsigned int i=0;i<dynColSize;i++) {
                outputFile_ << "|cc|";
            }
            outputFile_ << "}\n"
                << "\\caption{"
                << info_.gridname
                << ( info_.bfg ? std::string(", BFG ($\\tau = ")+ toString( info_.bfg_tau ) + std::string("$ "): std::string(", no BFG") )
                << " Polorder (u,p,$\\sigma$): (" << info_.polorder_velocity << ", "<< info_.polorder_pressure << ", "<< info_.polorder_sigma << " ) "
                << " Solver accuracy: " << info_.solver_accuracy
                << "}\\\\  \n"
                << "\\hline \n";

            for (unsigned int i=0;i<statColSize;i++) {
                outputFile_ << headers_[i];
                if ( i <  statColSize - 1 )
                    outputFile_ << " & ";
            }
            for (unsigned int i=0;i<dynColSize;i++) {
                outputFile_ << " & " << headers_[i+statColSize]
                    << " & EOC ";
            }
            outputFile_ << "\n \\endhead\n"
                        << "\\hline\n"
                        << "\\hline\n";
        }

        void putStaticCols( std::ofstream& outputFile_ )
        {
            std::stringstream runtime;
            if ( info_.run_time > 59 )
                runtime << long(info_.run_time) / 60 << ":" << long(info_.run_time) % 60 ;
            else
                runtime << long(info_.run_time) ;

            outputFile_ << std::setw( 4 )
                << info_.grid_width << " & "
                << info_.codim0 << " & "
                << runtime.str() << " & "
                << info_.c11 << " & "
                << info_.d11 << " & "
                << info_.c12 << " & "
                << info_.d12 ;

        }

        void endTable( std::ofstream& outputFile_ )
        {
            outputFile_ << "\\end{longtable}";
            outputFile_.flush();
        }

        double get_h ()
        {
            return current_h_;
        }
};

/**
 *  \brief Only free mem pointed to by valid pointer, log warning otherwise
 *
 **/

template < class T >
void safe_delete ( T t ) //this is actually bullshit :P
{
    if (t){
        delete t;
        t=0;
    }
    //else log warning
}

template < class Container, class Element >
int getIdx( const Container& ct, Element e )
{
    int idx = 0;
    for ( typename Container::const_iterator it = ct.begin(); it != ct.end(); ++it, ++idx )
    {
        if ( *it == e )
            return idx;
    }
    return -1;
}

//! strip filename from \path if present, return empty string if only filename present
std::string pathOnly ( std::string path )
{
    if (!path.empty())
    {
        char buf[1024];//not _exactly_ sure this is max path length, but it's suggested in wx source

        // Local copy
        strcpy (buf, path.c_str() );

        int l = path.length();
        int i = l - 1;

        // Search backward for a backward or forward slash
        while (i > -1)
        {
            if ( ( path[i] == '/' ) || ( path[i] == '\\' ) )
            {
                // Don't return an empty string
                if (i == 0)
                    i ++;
                buf[i] = 0;
                return std::string(buf);
            }
            i --;
        }
    }
    return std::string();
}

//! may include filename, will be stripped
bool testCreateDirectory( std::string path ) {
    std::string pathonly = pathOnly(path);
    if ( pathonly.empty() )
        return true; //no dir to create

    //maybe test if dir exists??
    bool ok = ( mkdir(pathonly.c_str(), 0755 ) == 0 );
    if ( !ok ) {
        perror( pathonly.c_str() );
        return errno == EEXIST;
    }
    return true;
}

} // end namepspace stuff

#endif // end of stuff.hh
<|endoftext|>


<commit_before>#include <c4/substr.hpp>
#include <c4/std/string.hpp>
#include <c4/fs/fs.hpp>
#include <c4/log/log.hpp>

#include <c4/yml/tree.hpp>
#include <c4/yml/parse.hpp>
#include <c4/yml/emit.hpp>

#include <gtest/gtest.h>

enum : size_t { npos = c4::csubstr::npos };

struct SuiteCase
{
    c4::csubstr filename;
    std::string file_contents;

    c4::csubstr desc;
    c4::csubstr from;
    c4::csubstr tags;

    c4::csubstr in_yaml;
    std::string in_yaml_filtered;

    c4::csubstr in_json;
    c4::csubstr out_yaml;
    c4::csubstr events;

    std::string in_yaml_in_situ;
    c4::yml::Tree in_tree_in_situ;
    c4::yml::Tree in_tree;

    bool load(const char* filename_)
    {
        filename = c4::to_csubstr(filename_);

        // read the file
        c4::fs::file_get_contents(filename_, &file_contents);
        c4::csubstr contents = to_csubstr(file_contents);

        // now parse the file
        c4::csubstr ws = " \t\r\n";
        size_t b, e;

        // desc
        C4_CHECK(contents.begins_with("=== "));
        e = contents.find("--- from: ", 4);
        C4_CHECK(e != npos);
        desc = contents.range(4, e).trimr(ws);

        // from
        b = e + 4;
        e = contents.find("--- tags: ", b);
        C4_CHECK(e != npos);
        from = contents.range(b, e);
        C4_CHECK(from.begins_with("from: "));
        C4_CHECK(from.size() >= 6);
        from = from.sub(6).trimr(ws);

        // tags
        b = e + 4;
        e = contents.find("--- in-yaml", b);
        C4_CHECK(e != npos);
        tags = contents.range(b, e);
        C4_CHECK(tags.begins_with("tags: "));
        C4_CHECK(tags.size() >= 6);
        tags = tags.sub(6).trimr(ws);
        if(tags.find("error") != npos) return false;

        // in_yaml
        b = e + 4;
        b = 1 + contents.find('\n', b);
        e = contents.find("--- in-json");
        in_yaml = contents.range(b, e).trimr(ws);

        // in_json
        b = e + 4;
        b = 1 + contents.find('\n', b);
        e = contents.find("--- test-event");
        in_json = contents.range(b, e).trimr(ws);

        // events
        b = e + 4;
        b = 1 + contents.find('\n', b);
        events = contents.range(b).trimr(ws);

        // filter
        if(tags.find("whitespace") != npos)
        {
            in_yaml_filtered.clear();
            b = 0;
            do {
                e = in_yaml.find("<SPC>", b);
                if(e == npos)
                {
                    in_yaml_filtered.append(&in_yaml[b], in_yaml.end());
                    break;
                }
                in_yaml_filtered.append(&in_yaml[b], &in_yaml[e]);
                in_yaml_filtered.append(" ");
                b = e + 5;
            } while(b != npos);
            in_yaml = to_csubstr(in_yaml_filtered);
        }

        return true;
    }

    void print() const
    {
        c4::printvar("% desc   : " , desc   , " %\n",
                     "% from   : " , from   , " %\n",
                     "% tags   : " , tags   , " %\n",
                     "% in_yaml:\n", in_yaml, " %\n",
                     "% in_json:\n", in_json, " %\n",
                     "% events :\n", events , " %\n");
    }

    void parse()
    {
        c4::yml::parse(filename, in_yaml, &in_tree);
    }

    void parse_in_situ()
    {
        in_yaml_in_situ.assign(in_yaml.begin(), in_yaml.end());
        c4::yml::parse(filename, to_substr(in_yaml_in_situ), &in_tree_in_situ);
    }
};

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

SuiteCase g_suite_case;

int main(int argc, char* argv[])
{
    // check input
    C4_CHECK(argc == 2);
    if(argc < 2) return 1;
    C4_CHECK(c4::fs::path_exists(argv[1]));

    if( ! g_suite_case.load(argv[1]))
    {
        return 0;
    }

    c4::print(g_suite_case.file_contents);
    g_suite_case.print();

    ::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}

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

TEST(parse_yaml, in_situ)
{
    g_suite_case.parse_in_situ();
}

TEST(parse_yaml, out_of_situ)
{
    g_suite_case.parse();
}
<commit_msg>improving unit tests for the yaml test suite<commit_after>#include <c4/substr.hpp>
#include <c4/std/string.hpp>
#include <c4/fs/fs.hpp>
#include <c4/log/log.hpp>

#include <c4/yml/tree.hpp>
#include <c4/yml/parse.hpp>
#include <c4/yml/emit.hpp>

#include <gtest/gtest.h>

enum : size_t { npos = c4::csubstr::npos };

struct Parsed
{
    bool was_parsed, was_emitted;
    c4::yml::Tree tree;
    std::string emitted;
};

struct Parsable
{
    c4::csubstr ro; // read-only  (copied to tree's arena before parsing)
    std::string rw; // read/write (parsed in situ)
    Parsed      ro_parsed;
    Parsed      rw_parsed;

    Parsable() { init(""); }

    void init(c4::csubstr contents)
    {
        ro = contents;
        rw.assign(ro.begin(), ro.end());
        ro_parsed.was_parsed = false;
        rw_parsed.was_parsed = false;
        ro_parsed.was_emitted = false;
        rw_parsed.was_emitted = false;
    }

    bool empty() const
    {
        return ro.empty();
    }

    void parse_ro()
    {
        if(empty()) return;
        c4::yml::parse(ro, &ro_parsed.tree);
        ro_parsed.was_parsed = true;
    }

    void parse_rw()
    {
        if(empty()) return;
        c4::yml::parse(to_substr(rw), &rw_parsed.tree);
        rw_parsed.was_parsed = true;
    }

    void emit_ro()
    {
        if(empty()) return;
        if(!ro_parsed.was_parsed) parse_ro();
        c4::yml::emit_resize(ro_parsed.tree, &ro_parsed.emitted);
        ro_parsed.was_emitted = true;
    }

    void emit_rw()
    {
        if(empty()) return;
        if(!rw_parsed.was_parsed) parse_rw();
        c4::yml::emit_resize(rw_parsed.tree, &rw_parsed.emitted);
        rw_parsed.was_emitted = true;
    }

    void compare_src()
    {
        if(empty()) return;
        EXPECT_EQ(std::string(ro.begin(), ro.end()), rw);
    }
    void compare_emitted()
    {
        if(empty()) return;
        if(!ro_parsed.was_parsed) parse_ro();
        if(!rw_parsed.was_parsed) parse_rw();
        if(!ro_parsed.was_emitted) emit_ro();
        if(!rw_parsed.was_emitted) emit_rw();
        EXPECT_EQ(ro_parsed.emitted, rw_parsed.emitted);
    }
};

struct SuiteCase
{
    c4::csubstr filename;
    std::string file_contents;

    c4::csubstr desc;
    c4::csubstr from;
    c4::csubstr tags;

    std::string in_yaml_filtered;
    Parsable    in_yaml;
    Parsable    in_json;
    Parsable    out_yaml;

    c4::csubstr events;

    bool load(const char* filename_)
    {
        filename = c4::to_csubstr(filename_);

        // read the file
        c4::fs::file_get_contents(filename_, &file_contents);
        c4::csubstr contents = to_csubstr(file_contents);

        // now parse the file
        c4::csubstr ws = " \t\r\n";
        c4::csubstr txt;
        size_t b, e;

        // desc
        C4_CHECK(contents.begins_with("=== "));
        e = contents.find("--- from: ", 4);
        C4_CHECK(e != npos);
        desc = contents.range(4, e).trimr(ws);

        // from
        b = e + 4;
        e = contents.find("--- tags: ", b);
        C4_CHECK(e != npos);
        from = contents.range(b, e);
        C4_CHECK(from.begins_with("from: "));
        C4_CHECK(from.size() >= 6);
        from = from.sub(6).trimr(ws);

        // tags
        b = e + 4;
        e = contents.find("--- in-yaml", b);
        C4_CHECK(e != npos);
        tags = contents.range(b, e);
        C4_CHECK(tags.begins_with("tags: "));
        C4_CHECK(tags.size() >= 6);
        tags = tags.sub(6).trimr(ws);

        if(tags.find("error") != npos) return false; // MARKED WITH ERROR. SKIP THE REST!

        size_t end_tags = e;
        size_t begin_in_yaml  = contents.find("--- in-yaml"   , end_tags);
        size_t begin_in_json  = contents.find("--- in-json"   , end_tags);
        size_t begin_out_yaml = contents.find("--- out-yaml"  , end_tags);
        size_t begin_events   = contents.find("--- test-event", end_tags);
        size_t first_after_yaml = std::min(begin_in_json, std::min(begin_out_yaml, begin_events));
        size_t first_after_json = std::min(begin_out_yaml, begin_events);

        // in_yaml
        C4_CHECK(begin_in_yaml != npos);
        begin_in_yaml = 1 + contents.find('\n', begin_in_yaml); // skip this line
        txt = contents.range(begin_in_yaml, first_after_yaml).trimr(ws);
        in_yaml.init(txt);

        // in_json
        if(begin_in_json != npos)
        {
            begin_in_json = 1 + contents.find('\n', begin_in_json); // skip this line
            txt = contents.range(begin_in_json, first_after_json).trimr(ws);
            in_json.init(txt);
        }

        // out_yaml
        if(begin_out_yaml != npos)
        {
            if(begin_in_json == npos) begin_in_json = begin_in_yaml;
            begin_out_yaml = 1 + contents.find('\n', begin_out_yaml); // skip this line
            txt = contents.range(begin_in_json, begin_events).trimr(ws);
            out_yaml.init(txt);
        }

        // events
        C4_CHECK(begin_events != npos);
        begin_events = 1 + contents.find('\n', begin_events); // skip this line
        events = contents.sub(begin_events).trimr(ws);

        // filter
        if(tags.find("whitespace") != npos)
        {
            auto y = in_yaml.ro;
            in_yaml_filtered.clear();
            b = 0;
            do {
                e = y.find("<SPC>", b);
                if(e == npos)
                {
                    in_yaml_filtered.append(&y[b], y.end());
                    break;
                }
                in_yaml_filtered.append(&y[b], &y[e]);
                in_yaml_filtered.append(" ");
                b = e + 5;
            } while(b != npos);
            in_yaml.init(to_csubstr(in_yaml_filtered));
        }

        return true;
    }

    void print() const
    {
        c4::printvar("% desc   : "  , desc       , " %\n",
                     "% from   : "  , from       , " %\n",
                     "% tags   : "  , tags       , " %\n",
                     "% in_yaml:\n" , in_yaml.ro , " %\n",
                     "% in_json:\n" , in_json.ro , " %\n",
                     "% out_yaml:\n", out_yaml.ro, " %\n",
                     "% events :\n" , events     , " %\n");
    }

};

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

SuiteCase g_suite_case;

int main(int argc, char* argv[])
{
    // check input
    C4_CHECK(argc == 2);
    if(argc < 2) return 1;
    C4_CHECK(c4::fs::path_exists(argv[1]));

    if( ! g_suite_case.load(argv[1]))
    {
        return 0;
    }

    c4::print(g_suite_case.file_contents);
    g_suite_case.print();

    ::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}

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

TEST(out_yaml_rw, parse)
{
    g_suite_case.out_yaml.parse_rw();
}
TEST(out_yaml_rw, emit)
{
    g_suite_case.out_yaml.emit_rw();
}

TEST(out_yaml_ro, parse)
{
    g_suite_case.out_yaml.parse_ro();
}
TEST(out_yaml_ro, emit)
{
    g_suite_case.out_yaml.emit_ro();
}

TEST(out_yaml_roVSrw, compare_src)
{
    g_suite_case.out_yaml.compare_src();
}

TEST(out_yaml_roVSrw, compare_emitted)
{
    g_suite_case.out_yaml.compare_emitted();
}

//-----------------------------------------------------------------------------
TEST(in_yaml_rw, parse)
{
    g_suite_case.in_yaml.parse_rw();
}
TEST(in_yaml_rw, emit)
{
    g_suite_case.in_yaml.emit_rw();
}

TEST(in_yaml_ro, parse)
{
    g_suite_case.in_yaml.parse_ro();
}
TEST(in_yaml_ro, emit)
{
    g_suite_case.in_yaml.emit_ro();
}

//-----------------------------------------------------------------------------
TEST(in_json_rw, parse)
{
    g_suite_case.in_json.parse_rw();
}
TEST(in_json_rw, emit)
{
    g_suite_case.in_json.emit_rw();
}

TEST(in_json_ro, parse)
{
    g_suite_case.in_json.parse_ro();
}
TEST(in_json_ro, emit)
{
    g_suite_case.in_json.emit_ro();
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Flowgrammable.org
// All rights reserved

#ifndef LIBMATCH_HASH_HPP
#define LIBMATCH_HASH_HPP

// The hashing module...
//
// TODO: Actually document the hash table.

#include <vector>
#include <boost/optional.hpp>

namespace hash_table
{
static size_t const primes[] = {
          53,        97,       193,       389,       769,
        1543,      3079,      6151,     12289,     24593,
       49157,     98317,    196613,    393241,    786433,
     1572869,   3145739,   6291469,  12582917,  25165843,
    50331653, 100663319, 201326611, 402653189, 805306457,
  1610612741,
};
static size_t const nprimes = sizeof(primes) / sizeof(size_t);

namespace data_store
{

// A key-value pair
template<typename K, typename V>
struct key_value
{
  key_value()
    : key(K()), val(V())
  { }

  key_value(K const& k, V const& v)
    : key(k), val(v)
  { }

  K key;
  V val;
};

// A basic entry type
template<typename K, typename V>
struct entry
{
  entry()
    : key(), val()
  { }

  entry(K const& k, V const& v)
    : key(k), val(v)
  { }

  K key;
  V val;
};

// A linked key-value pair
template<typename K, typename V>
struct list_entry : entry<K, V>
{
  list_entry()
    : entry<K, V>(), next(nullptr)
  { }

  list_entry(K const& k, V const& v)
    : entry<K, V>(k, v), next(nullptr)
  { }

  ~list_entry()
  {
    if (nullptr != next)
      delete next;
  }

  list_entry<K, V>* next;
};

// A tree node key-value pair
template<typename K, typename V>
struct tree_entry : entry<K, V>
{
  tree_entry()
    : entry<K, V>(), left(nullptr), right(nullptr)
  { }

  tree_entry(K const& k, V const& v)
    : entry<K, V>(k, v), left(nullptr), right(nullptr)
  { }

  tree_entry<K, V>* left;
  tree_entry<K, V>* right;
};

// A basic hash table bucket containing a single entry
template<typename T>
struct basic_bucket
{
  basic_bucket()
  { }

  basic_bucket(T const& v)
  {
    data_.emplace(v);
  }

  // Accessors

  // Retrieves the current value from the bucket. This can be a
  // usable value or the boost::none value to indicate it is not
  // set.
  boost::optional<T>
  open()
  {
    return (full() ? *data_ : boost::none);
  }

  // Checks if the bucket contains a usable value
  inline bool
  full()
  {
    return data_ != boost::none;
  }

  // Mutators

  // Adds an item to the bucket if it is not full
  void
  fill(T const& v)
  {
    if (!full())
      data_.emplace(v);
  }

  // Clears the bucket of its current value(s)
  void
  dump()
  {
    data_ = boost::none;
  }

  // Data members
  boost::optional<T> data_;
};

// A chained hash table bucket containing chained entries
template<typename K, typename V>
struct list_bucket
{
  list_bucket()
    : head(nullptr), size(0), empty(true)
  { }

  ~list_bucket()
  {
    if (nullptr != head)
      delete head;
  }

  bool
  is_empty()
  {
    return empty;
  }

  void
  add(K const& k, V const& v)
  {
    list_entry<K, V>* nh = new list_entry<K, V>(k, v);
    nh->next = head;
    head = nh;
    empty = false;
    size++;
  }

  void
  clear()
  {
    // TODO: implement this
    empty = true;
    size = 0;
  }

  list_entry<K, V>* head;
  int size;
  bool empty;
};

// An array based hash table bucket
template<typename K, typename V>
struct array_bucket
{

  array_bucket()
    : size(0), capacity(7), empty(true)
  {
    data = new entry<K, V>[capacity];
  }

  array_bucket(int n)
    : size(0), capacity(n), empty(true)
  {
    data = new entry<K, V>[n];
  }

  ~array_bucket()
  {
    delete[] data;
  }

  void
  add(K const& k, V const& v)
  {
    if (size + 1 < capacity) {
      data[size++] = entry<K, V>(k, v);
      empty = false;
    }
  }

  bool
  is_empty()
  {
    return empty;
  }

  void
  clear()
  {
    // TODO: implement this
    empty = true;
    size = 0;
  }

  entry<K, V>* data;
  int size;
  int capacity;
  bool empty;
};

// A tree based hash table bucket
// TODO: implement this using an array, not pointers
template<typename K, typename V>
struct tree_bucket : tree_entry<K, V>
{
  tree_bucket()
    : tree_entry<K, V>(), empty(true)
  { }

  tree_bucket(K const& k, V const& v)
    : tree_entry<K, V>(k, v), empty(false)
  { }

  ~tree_bucket()
  {
    // TODO: may need to do this different
    if (nullptr != this->left)
      delete this->left;
    if (nullptr != this->right)
      delete this->right;
  }

  void
  add(K const& k, V const& v)
  {
    // TODO: balance & sort the tree when adding to it
    this->key = k;
    this->val = v;
    empty = false;
  }

  bool
  is_empty()
  {
    return empty;
  }

  void
  clear()
  {
    // TODO: implement this
    empty = true;
  }

  bool empty;
};

} // end namespace data_store

// Encapsulates the open addressing hash table family
namespace open
{

// A hash table with open addressing and linear probing for
// resolving collisions.
template<typename K, typename V, typename H, typename C>
class linear
{
public:
  using store_type = std::vector<data_store::basic_bucket<data_store::entry<K, V>>>;
  using value_type = data_store::basic_bucket<data_store::entry<K, V>>;
  using hasher = H;
  using compare = C;

  linear()
    : linear(17)
  { }

  linear(int n)
    : linear(n, hasher(), compare())
  { }

  linear(int n, hasher h, compare c)
    : size_(0), buckets_(n), hash_(h), cmp_(c), data_(n)
  { }

  // Observers
  int size() const { return size_; }
  int buckets() const { return buckets_; }
  bool empty() const { return size_ == 0; }

  // Lookup
  value_type const* find(K const&) const;

  // Mutators
  value_type* insert(K const&, V const&);
  void erase(K const&);

private:
  int get_hash_index(K const&) const;
  int get_entry_index(K const&) const;

  // Resizes the hash table when the load reaches a particular value
  void resize();

private:
  int        size_;    // Current number of entries
  int        buckets_; // Number of buckets
  hasher     hash_;    // Hash function
  compare    cmp_;     // Equality comparison
  store_type data_;    // Data store
};

// Retrieves a key-value pair from the data store
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::find(K const& key) const -> value_type const*
{
  int idx = get_entry_index(key);
  if (idx < 0)
    return nullptr;
  return &data_[idx].open();
}

// Inserts a new key-value pair into an empty bucket.
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::insert(K const& key, V const& value) -> value_type*
{
  int idx = get_hash_index(key);
  while (!data_[idx].full())
    idx = (idx + 1 < buckets ? idx + 1 : 0);
  data_[idx].fill(data_store::entry<K, V>(key, value));
  ++size;
  return &data_[idx].open();
}

// Clears the bucket containing the same key, if found.
template<typename K, typename V, typename H, typename C>
void
linear<K, V, H, C>::erase(K const& key)
{
  int idx = get_entry_index(key);
  if (idx >= 0) {
    data_[idx].dump();
    --size;
  }
}

// Returns the index in the table for the given key or -1 if not found.
// This is guaranteed to be the actual index in the table for the key.
template<typename K, typename V, typename H, typename C>
int
linear<K, V, H, C>::get_entry_index(K const& key) const
{
  int idx = get_hash_index(key);
  while (!comp_(data_[idx], key))
    idx = (idx + 1 < buckets ? idx + 1 : 0);
  return (comp_(data_[idx], key) ? idx : -1);
}

// Returns an index in the table for a given key. This is not guaranteed
// to be the actual index for the key.
template<typename K, typename V, typename H, typename C>
inline int
linear<K, V, H, C>::get_hash_index(K const& key) const
{
  return hash(key) % buckets;
}

} //end namespace open

namespace closed
{

} // end namespace closed

} // end namespace hash_table

#endif<commit_msg>all of the bucket types now use boost::optionals<commit_after>// Copyright (c) 2015 Flowgrammable.org
// All rights reserved

#ifndef LIBMATCH_HASH_HPP
#define LIBMATCH_HASH_HPP

// The hashing module...
//
// TODO: Actually document the hash table.

#include <vector>
#include <boost/optional.hpp>

namespace hash_table
{
static size_t const primes[] = {
          53,        97,       193,       389,       769,
        1543,      3079,      6151,     12289,     24593,
       49157,     98317,    196613,    393241,    786433,
     1572869,   3145739,   6291469,  12582917,  25165843,
    50331653, 100663319, 201326611, 402653189, 805306457,
  1610612741,
};
static size_t const nprimes = sizeof(primes) / sizeof(size_t);

namespace data_store
{

// A key-value pair
template<typename K, typename V>
struct key_value
{
  key_value()
    : key(K()), val(V())
  { }

  key_value(K const& k, V const& v)
    : key(k), val(v)
  { }

  K key;
  V val;
};

// A basic entry type
template<typename K, typename V>
struct entry
{
  entry()
    : key(), val()
  { }

  entry(K const& k, V const& v)
    : key(k), val(v)
  { }

  K key;
  V val;
};

// A linked key-value pair
template<typename K, typename V>
struct list_entry : entry<K, V>
{
  list_entry()
    : entry<K, V>(), next(nullptr)
  { }

  list_entry(K const& k, V const& v)
    : entry<K, V>(k, v), next(nullptr)
  { }

  ~list_entry()
  {
    if (nullptr != next)
      delete next;
  }

  list_entry<K, V>* next;
};

// A tree node key-value pair
template<typename K, typename V>
struct tree_entry : entry<K, V>
{
  tree_entry()
    : entry<K, V>(), left(nullptr), right(nullptr)
  { }

  tree_entry(K const& k, V const& v)
    : entry<K, V>(k, v), left(nullptr), right(nullptr)
  { }

  tree_entry<K, V>* left;
  tree_entry<K, V>* right;
};

// A basic hash table bucket containing a single entry
template<typename T>
struct basic_bucket
{
  basic_bucket()
  { }

  basic_bucket(T const& v)
  {
    data_.emplace(v);
  }

  // Accessors

  // Retrieves the current value from the bucket. This can be a
  // usable value or the boost::none value to indicate it is not
  // set.
  boost::optional<T>
  open()
  {
    return (is_empty() ? boost::none : *data_);
  }

  // Checks if the bucket contains a usable value
  inline bool
  is_full()
  {
    return data_ != boost::none;
  }

  // Checks if the bucket does not contain a usable value
  inline bool
  is_empty()
  {
    return data_ == boost::none;
  }

  // Mutators

  // Adds an item to the bucket if it is not full
  void
  fill(T const& v)
  {
    if (!is_full())
      data_.emplace(v);
  }

  // Clears the bucket of its current value(s)
  void
  dump()
  {
    data_ = boost::none;
  }

  // Data Members
  boost::optional<T> data_;
};

// A chained hash table bucket containing chained entries
template<typename T>
struct list_bucket
{
  list_bucket()
  { }

  list_bucket(T const& v)
  {
    data_.emplace(v);
  }

  ~list_bucket()
  {
    // TODO: Same issue found in dump().
    data_ = boost::none;
  }

  // Accessors

  // Retrieves the entry from the bucket
  boost::optional<T>
  open()
  {
    return (is_empty() ? boost::none : *data_);
  }

  // Checks if the bucket contains any entries
  inline bool
  is_empty()
  {
    return data_ == boost::none;
  }

  // Mutators

  // Adds an entry to the bucket. Since this is an unbounded data store
  // type there is no concept of being 'full'.
  void
  fill(T const& v)
  {
    // If there are no other entries, add this one
    if (is_empty()) {
      data_.emplace(v);
    }
    // Else, have new entry point at old head
    else {
      v.next = *data_;
      // Destroy old data_
      data_ = boost::none;
      // Construct new data_
      data_.emplace(v);
    }
  }

  // Clears the bucket of its values
  void
  dump()
  {
    // TODO: This is probably not right. With a simple pointer list
    // we would probably need to walk the list and delete them. It has been
    // suggested to use a forward_list to avoid this issue.
    data_ = boost::none;
  }

  // Data Members

  boost::optional<T> data_;
};

// An array based hash table bucket
template<typename T>
struct array_bucket
{

  array_bucket()
    : array_bucket(10)
  { }

  array_bucket(int n)
    : size(0), capacity(n)
  {
    data_ = new boost::optional<T>[n];
  }

  ~array_bucket()
  {
    delete data_;
  }

  // Accesors

  // Retrieves the entries from the bucket
  boost::optional<T>*
  open()
  {
    return (is_empty() ? boost::none : data_);
  }

  // Checks if the bucket is at maximum capacity
  inline bool
  is_full()
  {
    return size == capacity - 1;
  }

  // Checks if the bucket contains any entries
  inline bool
  is_empty()
  {
    return size;
  }

  // Mutators

  // Adds an entry if the bucket is not full. Since this is a bounded
  // data store type there is a maximum number of entries that can be
  // held.
  void
  fill(T const& v)
  {
    if (size + 1 < capacity) {
      data_[size++].emplace(v);
    }
  }

  // Clears the bucket of its entries
  void
  dump()
  {
    delete data_;
    data_ = new boost::optional<T>[capacity];
    size = 0;
  }

  // Data Members
  boost::optional<T>* data_;  // Data store
  int size;                   // Current size
  int capacity;               // Maximum size
};

// A tree based hash table bucket
// TODO: implement this using an array, not pointers
template<typename T>
struct tree_bucket
{
  tree_bucket()
  { }

  tree_bucket(T const& v)
  {
    data_.emplace(v);
  }

  ~tree_bucket()
  {
    // TODO: Same issue as dump().
    data_ = boost::none;
  }

  // Accessors

  // Retrieves the entries from the bucket
  boost::optional<T>
  open()
  {
    return (is_empty() ? boost::none : *data_);
  }

  // Checks if the bucket contains any entries
  inline bool
  is_empty()
  {
    return data_ == boost::none;
  }

  // Mutators

  // Adds an entry to the bucket
  void
  fill(T const& v)
  {
    // TODO: balance & sort the tree when adding to it
    data_.emplace(v);
  }

  // Clears the bucket of any entries
  void
  dump()
  {
    // TODO: Same issue that list_bucket has. Will need to traverse
    // the tree and delete nodes.
    data_ = boost::none;
  }

  // Data Members
  boost::optional<T> data_;
};

} // end namespace data_store

// Encapsulates the open addressing hash table family
namespace open
{

// A hash table with open addressing and linear probing for
// resolving collisions.
template<typename K, typename V, typename H, typename C>
class linear
{
public:
  using store_type = std::vector<data_store::basic_bucket<data_store::entry<K, V>>>;
  using value_type = data_store::basic_bucket<data_store::entry<K, V>>;
  using hasher = H;
  using compare = C;

  linear()
    : linear(17)
  { }

  linear(int n)
    : linear(n, hasher(), compare())
  { }

  linear(int n, hasher h, compare c)
    : size_(0), buckets_(n), hash_(h), cmp_(c), data_(n)
  { }

  // Observers
  int size() const { return size_; }
  int buckets() const { return buckets_; }
  bool empty() const { return size_ == 0; }

  // Lookup
  value_type const* find(K const&) const;

  // Mutators
  value_type* insert(K const&, V const&);
  void erase(K const&);

private:
  int get_hash_index(K const&) const;
  int get_entry_index(K const&) const;

  // Resizes the hash table when the load reaches a particular value
  void resize();

private:
  int        size_;    // Current number of entries
  int        buckets_; // Number of buckets
  hasher     hash_;    // Hash function
  compare    cmp_;     // Equality comparison
  store_type data_;    // Data store
};

// Retrieves a key-value pair from the data store
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::find(K const& key) const -> value_type const*
{
  int idx = get_entry_index(key);
  if (idx < 0)
    return nullptr;
  return &data_[idx];
}

// Inserts a new key-value pair into an empty bucket.
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::insert(K const& key, V const& value) -> value_type*
{
  int idx = get_hash_index(key);
  while (data_[idx].is_full())
    idx = (idx + 1 < buckets ? idx + 1 : 0);
  data_[idx].fill(data_store::entry<K, V>(key, value));
  ++size;
  return &data_[idx];
}

// Clears the bucket containing the same key, if found.
template<typename K, typename V, typename H, typename C>
void
linear<K, V, H, C>::erase(K const& key)
{
  int idx = get_entry_index(key);
  if (idx >= 0) {
    data_[idx].dump();
    --size;
  }
}

// Returns the index in the table for the given key or -1 if not found.
// This is guaranteed to be the actual index in the table for the key.
template<typename K, typename V, typename H, typename C>
int
linear<K, V, H, C>::get_entry_index(K const& key) const
{
  int idx = get_hash_index(key);
  while (!cmp_(data_[idx], key))
    idx = (idx + 1 < buckets ? idx + 1 : 0);
  return (cmp_(data_[idx], key) ? idx : -1);
}

// Returns an index in the table for a given key. This is not guaranteed
// to be the actual index for the key.
template<typename K, typename V, typename H, typename C>
inline int
linear<K, V, H, C>::get_hash_index(K const& key) const
{
  return hash(key) % buckets;
}

} //end namespace open

namespace closed
{

} // end namespace closed

} // end namespace hash_table

#endif<|endoftext|>


<commit_before>#include "rubymotion.h"
#include <SimpleAudioEngine.h>

/// @class Audio < Object

VALUE rb_cAudio = Qnil;
static VALUE mc_audio_instance = Qnil;

/// @group Constructors

/// @method .shared
/// @return [Audio] the shared Audio instance.

static VALUE
audio_instance(VALUE rcv, SEL sel)
{
    if (mc_audio_instance == Qnil) {
	VALUE obj = rb_class_wrap_new(
		(void *)CocosDenshion::SimpleAudioEngine::getInstance(),
		rb_cAudio);
	mc_audio_instance = rb_retain(obj);
    }
    return mc_audio_instance;
}

static std::string
audio_path(VALUE path)
{
    std::string str = RSTRING_PTR(path);
    if (str.find('.') == std::string::npos) {
#if CC_TARGET_OS_IPHONE
	str.append(".caf");
#else
	str.append(".wav");
#endif
    }
    return str;
}

/// @group Audio Playback

/// @method #background(file_name, loop=true)
/// Plays background music.
/// @param file_name [String] Name of the audio file to play, without its file
///   extension. The file should reside in the application's resource
///   directory.
/// @param loop [true, false] Whether the audio file should loop.
/// @return [Audio] the receiver.

static VALUE
audio_background(VALUE rcv, SEL sel, int argc, VALUE *argv)
{
    VALUE path = Qnil;
    VALUE loop = Qtrue;

    rb_scan_args(argc, argv, "11", &path, &loop);

    AUDIO(rcv)->playBackgroundMusic(audio_path(path).c_str(), RTEST(loop));
    return rcv;
}

/// @method #effect(file_name)
/// Plays a sound effect.
/// @param file_name [String] Name of the audio file to play, without its file
///   extension. The file should reside in the application's resource
///   directory.
/// @return [Audio] the receiver.

static VALUE
audio_effect(VALUE rcv, SEL sel, VALUE path)
{
    AUDIO(rcv)->playEffect(audio_path(path).c_str());
    return rcv;
}

/// @group Properties

/// @property #background_volume
/// @return [Float] the volume of the background music within the range of 0.0
///   as the minimum and 1.0 as the maximum.

static VALUE
audio_background_volume(VALUE rcv, SEL sel)
{
    return DBL2NUM(AUDIO(rcv)->getBackgroundMusicVolume());
}

static VALUE
audio_background_volume_set(VALUE rcv, SEL sel, VALUE val)
{
    AUDIO(rcv)->setBackgroundMusicVolume(NUM2DBL(val));
    return val;
}

extern "C"
void
Init_Audio(void)
{
    rb_cAudio = rb_define_class_under(rb_mMC, "Audio", rb_cObject);

    rb_define_singleton_method(rb_cAudio, "shared", audio_instance, 0);
    rb_define_method(rb_cAudio, "background", audio_background, -1);
    rb_define_method(rb_cAudio, "background_volume", audio_background_volume,
	    0);
    rb_define_method(rb_cAudio, "background_volume=",
	    audio_background_volume_set, 1);
    rb_define_method(rb_cAudio, "effect", audio_effect, 1);
}
<commit_msg>new Audio API<commit_after>#include "rubymotion.h"
#include <AudioEngine.h>

/// @class Audio < Object

VALUE rb_cAudio = Qnil;

struct mc_Audio {
    int audio_id;
};

#define AUDIO_ENGINE cocos2d::experimental::AudioEngine

#define AUDIO_ID(obj) \
    ((_COCOS_WRAP_GET(obj, struct mc_Audio))->audio_id)

/// @group Constructors

/// @method .play(path, loop=false, volume=1.0)
/// Creates a new Audio object based on a sound file at the given path and
/// immediately plays it.
/// @param path [String] the path of the sound file that should be played.
/// @param loop [Boolean] whether the sound file playback should loop.
/// @param volume [Float] the audio volume that should be used to play this
///   this sound file, as a +0.0+ to +1.0+ Float range.
/// @return [Audio] an Audio instance.

static VALUE
audio_play(VALUE rcv, SEL sel, int argc, VALUE *argv)
{
    VALUE path = Qnil, loop = Qnil, volume = Qnil;

    rb_scan_args(argc, argv, "12", &path, &loop, &volume);

    std::string str = RSTRING_PTR(path);
    if (str.find('.') == std::string::npos) {
#if CC_TARGET_OS_IPHONE
	str.append(".caf");
#else
	str.append(".wav");
#endif
    }

    auto audio = new struct mc_Audio();
    audio->audio_id = AUDIO_ENGINE::play2d(str,
	loop == Qnil ? false : RTEST(loop),
	volume == Qnil ? 1.0 : NUM2DBL(volume));
    return rb_class_wrap_new((void *)audio, rb_cAudio);
}

/// @group Properties

/// @property #loop?
/// @return [Boolean] whether the sound file should loop.

static VALUE
audio_loop(VALUE rcv, SEL sel)
{
    return AUDIO_ENGINE::isLoop(AUDIO_ID(rcv)) ? Qtrue : Qfalse;
}

static VALUE
audio_loop_set(VALUE rcv, SEL sel, VALUE flag)
{
    AUDIO_ENGINE::setLoop(AUDIO_ID(rcv), RTEST(flag));
    return flag;
}

/// @property #volume
/// @return [Float] the volume of the sound file, from a 0.0 to 1.0 Float range.

static VALUE
audio_volume(VALUE rcv, SEL sel)
{
    return DBL2NUM(AUDIO_ENGINE::getVolume(AUDIO_ID(rcv)));
}

static VALUE
audio_volume_set(VALUE rcv, SEL sel, VALUE val)
{
    AUDIO_ENGINE::setVolume(AUDIO_ID(rcv), NUM2DBL(val));
    return val;
}

/// @property #current_position
/// @return [Float] the position where to play the sound file.

static VALUE
audio_current_position(VALUE rcv, SEL sel)
{
    return DBL2NUM(AUDIO_ENGINE::getCurrentTime(AUDIO_ID(rcv)));
}

static VALUE
audio_current_position_set(VALUE rcv, SEL sel, VALUE val)
{
    AUDIO_ENGINE::setCurrentTime(AUDIO_ID(rcv), NUM2DBL(val));
    return val;
}

/// @property-readonly #duration
/// @return [Float] the duration left in the sound file.

static VALUE
audio_duration(VALUE rcv, SEL sel)
{
    return DBL2NUM(AUDIO_ENGINE::getDuration(AUDIO_ID(rcv)));
}

/// @group Playback

/// @method #resume
/// Resumes playing the sound file.
/// @return [Audio] the receiver.

static VALUE
audio_resume(VALUE rcv, SEL sel)
{
    AUDIO_ENGINE::resume(AUDIO_ID(rcv));
    return rcv;
}

/// @method #pause
/// Pauses the sound file.
/// @return [Audio] the receiver.

static VALUE
audio_pause(VALUE rcv, SEL sel)
{
    AUDIO_ENGINE::pause(AUDIO_ID(rcv));
    return rcv;
}

/// @method #stop
/// Stops the sound file.
/// @return [Audio] the receiver.

static VALUE
audio_stop(VALUE rcv, SEL sel)
{
    AUDIO_ENGINE::stop(AUDIO_ID(rcv));
    return rcv;
}

/// @method #playing?
/// @return [Boolean] whether the sound file is being played.

static VALUE
audio_playing(VALUE rcv, SEL sel)
{
    return AUDIO_ENGINE::getState(AUDIO_ID(rcv))
	== AUDIO_ENGINE::AudioState::PLAYING ? Qtrue : Qfalse;
}

/// @method #paused?
/// @return [Boolean] whether the sound file is being paused.

static VALUE
audio_paused(VALUE rcv, SEL sel)
{
    return AUDIO_ENGINE::getState(AUDIO_ID(rcv))
	== AUDIO_ENGINE::AudioState::PAUSED ? Qtrue : Qfalse;
}

extern "C"
void
Init_Audio(void)
{
    rb_cAudio = rb_define_class_under(rb_mMC, "Audio", rb_cObject);

    rb_define_singleton_method(rb_cAudio, "play", audio_play, -1);
    rb_define_method(rb_cAudio, "loop?", audio_loop, 0);
    rb_define_method(rb_cAudio, "loop=", audio_loop_set, 1);
    rb_define_method(rb_cAudio, "volume", audio_volume, 0);
    rb_define_method(rb_cAudio, "volume=", audio_volume_set, 1);
    rb_define_method(rb_cAudio, "current_position", audio_current_position, 0);
    rb_define_method(rb_cAudio, "current_position=",
	    audio_current_position_set, 1);
    rb_define_method(rb_cAudio, "duration", audio_duration, 0);
    rb_define_method(rb_cAudio, "resume", audio_resume, 0);
    rb_define_method(rb_cAudio, "pause", audio_pause, 0);
    rb_define_method(rb_cAudio, "stop", audio_stop, 0);
    rb_define_method(rb_cAudio, "playing?", audio_playing, 0);
    rb_define_method(rb_cAudio, "paused?", audio_paused, 0);
}
<|endoftext|>


<commit_before>/*!
*	@file	libpsalm_test.cpp
*	@brief	Test suite for libpsalm
*	@author	Bastian Rieck <bastian.rieck@iwr.uni-heidelberg.de>
*
*	This test suite reads a .pline file, converts it to a format suitable
*	for libpsalm, and writes the output file back into native PLY format.
*/

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

#include "libpsalm.h"
#include "hole.h"

/*!
*	Processes the given .pline file by reading it and converting it to a
*	format suitable for libpsalm.
*
*	@param filename File to process
*/

void process_pline_file(std::string filename)
{
	std::ifstream in(filename.c_str());
	if(!in.good())
	{
		std::cerr	<< "pline_fill: Unable to open .pline file \""
				<< filename << "\"."
				<< std::endl;
		return;
	}
	else
		std::cout << "pline_fill: Processing file \"" << filename << "\" " << std::flush;

	std::string line;
	std::stringstream converter;

	while(std::getline(in, line))
	{
		// Ignore lines containing a "#"
		if(line.find_first_of('#') != std::string::npos)
			continue;

		converter.str(line);

		// Data format is straightforward (different fields are assumed to
		// be separated by whitespace).
		//
		//	Label ID | number of vertices | id1 x1 y1 z1 n1 n2 n3 id2 x2 y2 z2 ...

		size_t label_no;
		size_t num_vertices;

		converter >> label_no >> num_vertices;

		// Prepare storage for vertex IDs and vertex coordinates
		long* vertex_IDs = new long[num_vertices-1];
		double* coordinates = new double[3*(num_vertices-1)];

		for(size_t i = 0; i < num_vertices-1; i++)	// ignore last point because it is a repetition of
								// the first point
		{
			converter	>> vertex_IDs[i]
					>> coordinates[3*i]
					>> coordinates[3*i+1]
					>> coordinates[3*i+2];

			// XXX: Ignore normals
			double dummy;
			converter >> dummy >> dummy >> dummy;
		}

		// Storage for data returned by the algorithm
		int num_new_vertices	= 0;
		double* new_coordinates = NULL;
		int num_new_faces	= 0;
		long* new_vertex_IDs	= NULL;

		fill_hole(	num_vertices, vertex_IDs, coordinates,
				&num_new_vertices, &new_coordinates, &num_new_faces, &new_vertex_IDs);

		delete[] vertex_IDs;
		delete[] coordinates;

		delete[] new_coordinates;
		delete[] new_vertex_IDs;

		converter.clear();
		line.clear();

		std::cout << "." << std::flush;
	}

	std::cout << "done." << std::endl;
}

int main(int argc, char* argv[])
{
	process_pline_file("../Holes/Salmanassar3_Holes_w_Normals_HR_CLEAN_with_Indices.pline");
	return(0);
}
<commit_msg>Corrected bug in libpsalm_test<commit_after>/*!
*	@file	libpsalm_test.cpp
*	@brief	Test suite for libpsalm
*	@author	Bastian Rieck <bastian.rieck@iwr.uni-heidelberg.de>
*
*	This test suite reads a .pline file, converts it to a format suitable
*	for libpsalm, and writes the output file back into native PLY format.
*/

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

#include "libpsalm.h"
#include "hole.h"

/*!
*	Processes the given .pline file by reading it and converting it to a
*	format suitable for libpsalm.
*
*	@param filename File to process
*/

void process_pline_file(std::string filename)
{
	std::ifstream in(filename.c_str());
	if(!in.good())
	{
		std::cerr	<< "pline_fill: Unable to open .pline file \""
				<< filename << "\"."
				<< std::endl;
		return;
	}
	else
		std::cout << "pline_fill: Processing file \"" << filename << "\" " << std::flush;

	std::string line;
	std::stringstream converter;

	while(std::getline(in, line))
	{
		// Ignore lines containing a "#"
		if(line.find_first_of('#') != std::string::npos)
			continue;

		converter.str(line);

		// Data format is straightforward (different fields are assumed to
		// be separated by whitespace).
		//
		//	Label ID | number of vertices | id1 x1 y1 z1 n1 n2 n3 id2 x2 y2 z2 ...

		int label_no;
		int num_vertices;

		converter >> label_no >> num_vertices;
		num_vertices--;	// ignore last point because it is a repetition
				// of the first point

		// Prepare storage for vertex IDs and vertex coordinates
		long* vertex_IDs = new long[num_vertices];
		double* coordinates = new double[3*num_vertices];

		for(int i = 0; i < num_vertices; i++)
		{
			converter	>> vertex_IDs[i]
					>> coordinates[3*i]
					>> coordinates[3*i+1]
					>> coordinates[3*i+2];

			// XXX: Ignore normals
			double dummy;
			converter >> dummy >> dummy >> dummy;
		}

		// Storage for data returned by the algorithm
		int num_new_vertices	= 0;
		double* new_coordinates = NULL;
		int num_new_faces	= 0;
		long* new_vertex_IDs	= NULL;

		fill_hole(	num_vertices, vertex_IDs, coordinates,
				&num_new_vertices, &new_coordinates, &num_new_faces, &new_vertex_IDs);

		delete[] vertex_IDs;
		delete[] coordinates;

		delete[] new_coordinates;
		delete[] new_vertex_IDs;

		converter.clear();
		line.clear();

		std::cout << "." << std::flush;
	}

	std::cout << "done." << std::endl;
}

int main(int argc, char* argv[])
{
	process_pline_file("../Holes/Salmanassar3_Holes_w_Normals_HR_CLEAN_with_Indices.pline");
	return(0);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bloom.h>

#include <primitives/transaction.h>
#include <hash.h>
#include <script/script.h>
#include <script/standard.h>
#include <random.h>
#include <streams.h>

#include <math.h>
#include <stdlib.h>

#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552

CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :
    /**
     * The ideal size for a bloom filter with a given number of elements and false positive rate is:
     * - nElements * log(fp rate) / ln(2)^2
     * We ignore filter parameters which will create a bloom filter larger than the protocol limits
     */
    vData(std::min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
    /**
     * The ideal number of hash functions is filter size * ln(2) / number of elements
     * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
     * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
     */
    isFull(false),
    isEmpty(false),
    nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
    nTweak(nTweakIn),
    nFlags(nFlagsIn)
{
}

// Private constructor used by CRollingBloomFilter
CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn) :
    vData((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)) / 8),
    isFull(false),
    isEmpty(true),
    nHashFuncs((unsigned int)(vData.size() * 8 / nElements * LN2)),
    nTweak(nTweakIn),
    nFlags(BLOOM_UPDATE_NONE)
{
}

inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
{
    // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}

void CBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
    if (isFull)
        return;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Sets bit nIndex of vData
        vData[nIndex >> 3] |= (1 << (7 & nIndex));
    }
    isEmpty = false;
}

void CBloomFilter::insert(const COutPoint& outpoint)
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    std::vector<unsigned char> data(stream.begin(), stream.end());
    insert(data);
}

void CBloomFilter::insert(const uint256& hash)
{
    std::vector<unsigned char> data(hash.begin(), hash.end());
    insert(data);
}

bool CBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Checks bit nIndex of vData
        if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
            return false;
    }
    return true;
}

bool CBloomFilter::contains(const COutPoint& outpoint) const
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    std::vector<unsigned char> data(stream.begin(), stream.end());
    return contains(data);
}

bool CBloomFilter::contains(const uint256& hash) const
{
    std::vector<unsigned char> data(hash.begin(), hash.end());
    return contains(data);
}

void CBloomFilter::clear()
{
    vData.assign(vData.size(),0);
    isFull = false;
    isEmpty = true;
}

void CBloomFilter::reset(const unsigned int nNewTweak)
{
    clear();
    nTweak = nNewTweak;
}

bool CBloomFilter::IsWithinSizeConstraints() const
{
    return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}

bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
{
    bool fFound = false;
    // Match if the filter contains the hash of tx
    //  for finding tx when they appear in a block
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    const uint256& hash = tx.GetHash();
    if (contains(hash))
        fFound = true;

    for (unsigned int i = 0; i < tx.vout.size(); i++)
    {
        const CTxOut& txout = tx.vout[i];
        // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
        // If this matches, also add the specific output that was matched.
        // This means clients don't have to update the filter themselves when a new relevant tx
        // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
        CScript::const_iterator pc = txout.scriptPubKey.begin();
        std::vector<unsigned char> data;
        while (pc < txout.scriptPubKey.end())
        {
            opcodetype opcode;
            if (!txout.scriptPubKey.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
            {
                fFound = true;
                if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
                    insert(COutPoint(hash, i));
                else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
                {
                    txnouttype type;
                    std::vector<std::vector<unsigned char> > vSolutions;
                    if (Solver(txout.scriptPubKey, type, vSolutions) &&
                            (type == TX_PUBKEY || type == TX_MULTISIG))
                        insert(COutPoint(hash, i));
                }
                break;
            }
        }
    }

    if (fFound)
        return true;

    for (const CTxIn& txin : tx.vin)
    {
        // Match if the filter contains an outpoint tx spends
        if (contains(txin.prevout))
            return true;

        // Match if the filter contains any arbitrary script data element in any scriptSig in tx
        CScript::const_iterator pc = txin.scriptSig.begin();
        std::vector<unsigned char> data;
        while (pc < txin.scriptSig.end())
        {
            opcodetype opcode;
            if (!txin.scriptSig.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
                return true;
        }
    }

    return false;
}

void CBloomFilter::UpdateEmptyFull()
{
    bool full = true;
    bool empty = true;
    for (unsigned int i = 0; i < vData.size(); i++)
    {
        full &= vData[i] == 0xff;
        empty &= vData[i] == 0;
    }
    isFull = full;
    isEmpty = empty;
}

CRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)
{
    double logFpRate = log(fpRate);
    /* The optimal number of hash functions is log(fpRate) / log(0.5), but
     * restrict it to the range 1-50. */
    nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));
    /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
    nEntriesPerGeneration = (nElements + 1) / 2;
    uint32_t nMaxElements = nEntriesPerGeneration * 3;
    /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
     * =>          pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
     */
    uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
    data.clear();
    /* For each data element we need to store 2 bits. If both bits are 0, the
     * bit is treated as unset. If the bits are (01), (10), or (11), the bit is
     * treated as set in generation 1, 2, or 3 respectively.
     * These bits are stored in separate integers: position P corresponds to bit
     * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
    data.resize(((nFilterBits + 63) / 64) << 1);
    reset();
}

/* Similar to CBloomFilter::Hash */
static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char>& vDataToHash) {
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
}

void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
    if (nEntriesThisGeneration == nEntriesPerGeneration) {
        nEntriesThisGeneration = 0;
        nGeneration++;
        if (nGeneration == 4) {
            nGeneration = 1;
        }
        uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);
        uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);
        /* Wipe old entries that used this generation number. */
        for (uint32_t p = 0; p < data.size(); p += 2) {
            uint64_t p1 = data[p], p2 = data[p + 1];
            uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
            data[p] = p1 & mask;
            data[p + 1] = p2 & mask;
        }
    }
    nEntriesThisGeneration++;

    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        uint32_t pos = (h >> 6) % data.size();
        /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
        data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
        data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
    }
}

void CRollingBloomFilter::insert(const uint256& hash)
{
    std::vector<unsigned char> data(hash.begin(), hash.end());
    insert(data);
}

bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        uint32_t pos = (h >> 6) % data.size();
        /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
        if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
            return false;
        }
    }
    return true;
}

bool CRollingBloomFilter::contains(const uint256& hash) const
{
    std::vector<unsigned char> data(hash.begin(), hash.end());
    return contains(data);
}

void CRollingBloomFilter::reset()
{
    nTweak = GetRand(std::numeric_limits<unsigned int>::max());
    nEntriesThisGeneration = 0;
    nGeneration = 1;
    for (std::vector<uint64_t>::iterator it = data.begin(); it != data.end(); it++) {
        *it = 0;
    }
}
<commit_msg>avoid shadowing<commit_after>// Copyright (c) 2012-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bloom.h>

#include <primitives/transaction.h>
#include <hash.h>
#include <script/script.h>
#include <script/standard.h>
#include <random.h>
#include <streams.h>

#include <math.h>
#include <stdlib.h>

#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552

CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :
    /**
     * The ideal size for a bloom filter with a given number of elements and false positive rate is:
     * - nElements * log(fp rate) / ln(2)^2
     * We ignore filter parameters which will create a bloom filter larger than the protocol limits
     */
    vData(std::min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
    /**
     * The ideal number of hash functions is filter size * ln(2) / number of elements
     * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
     * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
     */
    isFull(false),
    isEmpty(true),
    nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
    nTweak(nTweakIn),
    nFlags(nFlagsIn)
{
}

// Private constructor used by CRollingBloomFilter
CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn) :
    vData((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)) / 8),
    isFull(false),
    isEmpty(true),
    nHashFuncs((unsigned int)(vData.size() * 8 / nElements * LN2)),
    nTweak(nTweakIn),
    nFlags(BLOOM_UPDATE_NONE)
{
}

inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
{
    // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}

void CBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
    if (isFull)
        return;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Sets bit nIndex of vData
        vData[nIndex >> 3] |= (1 << (7 & nIndex));
    }
    isEmpty = false;
}

void CBloomFilter::insert(const COutPoint& outpoint)
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    std::vector<unsigned char> data(stream.begin(), stream.end());
    insert(data);
}

void CBloomFilter::insert(const uint256& hash)
{
    std::vector<unsigned char> data(hash.begin(), hash.end());
    insert(data);
}

bool CBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Checks bit nIndex of vData
        if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
            return false;
    }
    return true;
}

bool CBloomFilter::contains(const COutPoint& outpoint) const
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    std::vector<unsigned char> data(stream.begin(), stream.end());
    return contains(data);
}

bool CBloomFilter::contains(const uint256& hash) const
{
    std::vector<unsigned char> data(hash.begin(), hash.end());
    return contains(data);
}

void CBloomFilter::clear()
{
    vData.assign(vData.size(),0);
    isFull = false;
    isEmpty = true;
}

void CBloomFilter::reset(const unsigned int nNewTweak)
{
    clear();
    nTweak = nNewTweak;
}

bool CBloomFilter::IsWithinSizeConstraints() const
{
    return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}

bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
{
    bool fFound = false;
    // Match if the filter contains the hash of tx
    //  for finding tx when they appear in a block
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    const uint256& hash = tx.GetHash();
    if (contains(hash))
        fFound = true;

    for (unsigned int i = 0; i < tx.vout.size(); i++)
    {
        const CTxOut& txout = tx.vout[i];
        // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
        // If this matches, also add the specific output that was matched.
        // This means clients don't have to update the filter themselves when a new relevant tx
        // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
        CScript::const_iterator pc = txout.scriptPubKey.begin();
        std::vector<unsigned char> data;
        while (pc < txout.scriptPubKey.end())
        {
            opcodetype opcode;
            if (!txout.scriptPubKey.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
            {
                fFound = true;
                if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
                    insert(COutPoint(hash, i));
                else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
                {
                    txnouttype type;
                    std::vector<std::vector<unsigned char> > vSolutions;
                    if (Solver(txout.scriptPubKey, type, vSolutions) &&
                            (type == TX_PUBKEY || type == TX_MULTISIG))
                        insert(COutPoint(hash, i));
                }
                break;
            }
        }
    }

    if (fFound)
        return true;

    for (const CTxIn& txin : tx.vin)
    {
        // Match if the filter contains an outpoint tx spends
        if (contains(txin.prevout))
            return true;

        // Match if the filter contains any arbitrary script data element in any scriptSig in tx
        CScript::const_iterator pc = txin.scriptSig.begin();
        std::vector<unsigned char> data;
        while (pc < txin.scriptSig.end())
        {
            opcodetype opcode;
            if (!txin.scriptSig.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
                return true;
        }
    }

    return false;
}

void CBloomFilter::UpdateEmptyFull()
{
    bool full = true;
    bool empty = true;
    for (unsigned int i = 0; i < vData.size(); i++)
    {
        full &= vData[i] == 0xff;
        empty &= vData[i] == 0;
    }
    isFull = full;
    isEmpty = empty;
}

CRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)
{
    double logFpRate = log(fpRate);
    /* The optimal number of hash functions is log(fpRate) / log(0.5), but
     * restrict it to the range 1-50. */
    nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));
    /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
    nEntriesPerGeneration = (nElements + 1) / 2;
    uint32_t nMaxElements = nEntriesPerGeneration * 3;
    /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
     * =>          pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
     */
    uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
    data.clear();
    /* For each data element we need to store 2 bits. If both bits are 0, the
     * bit is treated as unset. If the bits are (01), (10), or (11), the bit is
     * treated as set in generation 1, 2, or 3 respectively.
     * These bits are stored in separate integers: position P corresponds to bit
     * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
    data.resize(((nFilterBits + 63) / 64) << 1);
    reset();
}

/* Similar to CBloomFilter::Hash */
static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char>& vDataToHash) {
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
}

void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
    if (nEntriesThisGeneration == nEntriesPerGeneration) {
        nEntriesThisGeneration = 0;
        nGeneration++;
        if (nGeneration == 4) {
            nGeneration = 1;
        }
        uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);
        uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);
        /* Wipe old entries that used this generation number. */
        for (uint32_t p = 0; p < data.size(); p += 2) {
            uint64_t p1 = data[p], p2 = data[p + 1];
            uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
            data[p] = p1 & mask;
            data[p + 1] = p2 & mask;
        }
    }
    nEntriesThisGeneration++;

    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        uint32_t pos = (h >> 6) % data.size();
        /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
        data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
        data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
    }
}

void CRollingBloomFilter::insert(const uint256& hash)
{
    std::vector<unsigned char> vData(hash.begin(), hash.end());
    insert(vData);
}

bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        uint32_t pos = (h >> 6) % data.size();
        /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
        if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
            return false;
        }
    }
    return true;
}

bool CRollingBloomFilter::contains(const uint256& hash) const
{
    std::vector<unsigned char> vData(hash.begin(), hash.end());
    return contains(vData);
}

void CRollingBloomFilter::reset()
{
    nTweak = GetRand(std::numeric_limits<unsigned int>::max());
    nEntriesThisGeneration = 0;
    nGeneration = 1;
    for (std::vector<uint64_t>::iterator it = data.begin(); it != data.end(); it++) {
        *it = 0;
    }
}
<|endoftext|>


<commit_before>#include <stack.hpp>
#include <catch.hpp>

SCENARIO("init", "[init]") {
	stack<int> A;
	REQUIRE(A.count() == 0);
}

SCENARIO("Push", "[push]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	REQUIRE(A.count() == 2);
}

SCENARIO("Pop", "[pop]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	A.pop();
	REQUIRE(A.count() == 1);
}

SCENARIO("oper=", "[oper]"){
	stack<int> A;
	stack<int> B;
	A.push(1);
	A.push(2);
	B.push(3);
	REQUIRE(A.count() == 2);
	B = A;
	REQUIRE(B.count() == 3);
}
<commit_msg>Update init.cpp<commit_after>#include <stack.hpp>
#include <catch.hpp>

SCENARIO("init", "[init]") {
	stack<int> A;
	REQUIRE(A.count() == 0);
}

SCENARIO("Push", "[push]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	REQUIRE(A.count() == 2);
}

SCENARIO("Pop", "[pop]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	A.pop();
	REQUIRE(A.count() == 1);
}

SCENARIO("oper=", "[oper]"){
	stack<int> A;
	stack<int> B;
	A.push(1);
	A.push(2);
	REQUIRE(A.count() == 2);
	B = A;
	REQUIRE(B.count() == 2);
}
<|endoftext|>