From 2fdb0eafe87b14fba088259c875489df8c6c7896 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Thu, 17 Mar 2016 15:10:11 +0100
Subject: [PATCH] add general alphabet class and tests

---
 alib2data/src/alphabet/Alphabet.hpp          | 365 +++++++++++++++++++
 alib2data/test-src/alphabet/AlphabetTest.cpp | 120 ++++++
 alib2data/test-src/alphabet/AlphabetTest.h   |  20 +
 3 files changed, 505 insertions(+)
 create mode 100644 alib2data/src/alphabet/Alphabet.hpp
 create mode 100644 alib2data/test-src/alphabet/AlphabetTest.cpp
 create mode 100644 alib2data/test-src/alphabet/AlphabetTest.h

diff --git a/alib2data/src/alphabet/Alphabet.hpp b/alib2data/src/alphabet/Alphabet.hpp
new file mode 100644
index 0000000000..ee5a330fc5
--- /dev/null
+++ b/alib2data/src/alphabet/Alphabet.hpp
@@ -0,0 +1,365 @@
+/*
+ * Alphabet.hpp
+ *
+ *  Created on: Mar 16, 2016
+ *      Author: Jan Travnicek
+ */
+
+#ifndef ALPHABET_HPP_
+#define ALPHABET_HPP_
+
+#include <set>
+#include <algorithm>
+#include <exception/AlibException.h>
+
+namespace alphabet {
+
+/**
+ * Represents an alphabet of symbols.
+ * @param Derived class representing datatype using this alphabet.
+ * @param SymbolType underlying type of symbols in the alphabet.
+ * @param AlphabetType arbirtrary type used to distinguish different alphabets.
+ */
+template < class Derived, class SymbolType, class AlphabetType >
+class Alphabet {
+	/**
+	 * The alphabet.
+	 */
+	std::set < SymbolType > data;
+
+public:
+	/*
+	 * Constructs an empty alphabet.
+	 */
+	Alphabet ( ) {
+	}
+
+	/**
+	 * Constructs an alphabet containing given symbols.
+	 * @throw AlibException if symbols are not available in context of datatype where the alphabet is used
+	 */
+	Alphabet ( std::set < SymbolType > symbols ) : data ( std::move ( symbols ) ) {
+		for ( const SymbolType & symbol : data ) {
+			valid ( symbol );
+
+			if ( !available ( symbol ) )
+				throw exception::AlibException ( "Symbol " + ( std::string ) symbol + " is not available." );
+		}
+	}
+
+	/**
+	 * Adds a symbol to the alphabet.
+	 * @param symbol to add to the alphabet
+	 * @throw AlibException if symbols are not available in context of datatype where the alphabet is used
+	 */
+	bool add ( SymbolType symbol ) {
+		valid ( symbol );
+
+		if ( !available ( symbol ) )
+			throw exception::AlibException ( "Symbol " + ( std::string ) symbol + " is not available." );
+		else
+			return data.insert ( std::move ( symbol ) ).second;
+	}
+
+	/**
+	 * Changes the alphabet.
+	 * @param symbols by which to replace those currently in the alphabet
+	 * @throw AlibException if symbol is used in context of datatype instance using the alphabet
+	 */
+	void set ( std::set < SymbolType > symbols ) {
+		std::set < SymbolType > removed;
+		std::set_difference ( data.begin ( ), data.end ( ), symbols.begin ( ), symbols.end ( ), std::inserter ( removed, removed.end ( ) ) );
+
+		for ( const SymbolType & symbol : removed )
+			remove ( symbol );
+
+		data = std::move ( symbols );
+	}
+
+	/**
+	 * @return set of symbols in the alphabet.
+	 */
+	const std::set < SymbolType > & get ( ) const {
+		return data;
+	}
+
+	/**
+	 * Removes a symbol from alphabet if not used.
+	 * @throw AlibException if symbol is used in context of datatype instance using the alphabet
+	 * @return true if symbol was indeed removed
+	 *         false if symbol was not present in the alphabet
+	 */
+	bool remove ( const SymbolType & symbol ) {
+		if ( used ( symbol ) )
+			throw exception::AlibException ( "Symbol " + ( std::string ) symbol + " is used." );
+		else
+			return data.erase ( symbol );
+	}
+
+	/**
+	 * Alphabet emptines checker.
+	 * @return true if alphabet is an empty
+	 */
+	bool empty ( ) const {
+		return data.empty ( );
+	}
+
+	/**
+	 * Checks whether a concrete symbol is used in context of the datatype instance using this alphabet
+	 *
+	 * To be implemented by all template instantiations explicitly
+	 *
+	 * @param symbol symbol to check
+	 * @return true if symbol is used
+	 *         false if symbol is not used
+	 */
+	bool used ( const SymbolType & symbol ) const;
+
+	/**
+	 * Checks whether a concrete symbol is available in context of the datatype instance using this alphabet
+	 *
+	 * To be implemented by all template instantiations explicitly
+	 *
+	 * @param symbol symbol to check
+	 * @return true if symbol is available
+	 *         false if symbol is not available
+	 */
+	bool available ( const SymbolType & symbol ) const;
+
+	/**
+	 * Checks whether a concrete symbol is valid in context of the datatype instance using this alphabet
+	 *
+	 * To be implemented by all template instantiations explicitly
+	 *
+	 * @param symbol symbol to check
+	 * @throw AlibException if the symbol in any way invalid
+	 */
+	void valid ( const SymbolType & symbol ) const;
+
+	/**
+	 * Compares alphabets for equality.
+	 * @param other another alphabet
+	 */
+	bool operator ==( const Alphabet & other ) const {
+		return data == other.data ( );
+	}
+
+	/**
+	 * Compares alphabets in natural order.
+	 * @param other another alphabet
+	 */
+	bool operator <( const Alphabet & other ) const {
+		return data < other.data ( );
+	}
+
+};
+
+/**
+ * Auxilary class packing multiple alphabets.
+ */
+template < class Derived, class SymbolType, class ... AlphabetTypes >
+class AlphabetPack;
+
+/**
+ * Auxilary class packing single alphabets.
+ */
+template < class Derived, class SymbolType, class AlphabetType1 >
+class AlphabetPack < Derived, SymbolType, AlphabetType1 > : public Alphabet < Derived, SymbolType, AlphabetType1 > {
+public:
+	/**
+	 * Construct an alphabet pack from single alphabet.
+	 */
+	AlphabetPack ( SymbolType first ) : Alphabet < Derived, SymbolType, AlphabetType1 > ( std::move ( first ) ) {
+	}
+
+};
+
+/**
+ * Auxilary class packing two alphabets.
+ */
+template < class Derived, class SymbolType, class AlphabetType1, class AlphabetType2 >
+class AlphabetPack < Derived, SymbolType, AlphabetType1, AlphabetType2 > : public Alphabet < Derived, SymbolType, AlphabetType1 >, public Alphabet < Derived, SymbolType, AlphabetType2 > {
+public:
+	/**
+	 * Construct an alphabet pack from two alphabets.
+	 */
+	AlphabetPack ( std::set < SymbolType > first, std::set < SymbolType > second ) : Alphabet < Derived, SymbolType, AlphabetType1 > ( std::move ( first ) ), Alphabet < Derived, SymbolType, AlphabetType2 > ( std::move ( second ) ) {
+	}
+
+};
+
+/**
+ * Auxilary class allowing simple access to the alphabets.
+ */
+template < class Derived, class SymbolType, class ... AlphabetTypes >
+class Alphabets : public AlphabetPack < Derived, SymbolType, AlphabetTypes ... > {
+public:
+	/**
+	 * Reuse constructor of the base class.
+	 */
+	using AlphabetPack < Derived, SymbolType, AlphabetTypes ... >::AlphabetPack;
+
+	/**
+	 * Allow acces to subalphabet using its type.
+	 * @param AlphabetType alphabet type used to distinguish different sub alphabets
+	 * @return subalphabet
+	 */
+	template < class AlphabetType >
+	const Alphabet < Derived, SymbolType, AlphabetType > & getAlphabet ( ) const {
+		return static_cast < const Alphabet < Derived, SymbolType, AlphabetType > & > ( * this );
+	}
+
+	/**
+	 * Allow acces to subalphabet using its type.
+	 * @param AlphabetType alphabet type used to distinguish different sub alphabets
+	 * @return subalphabet
+	 */
+	template < class AlphabetType >
+	Alphabet < Derived, SymbolType, AlphabetType > & getAlphabet ( ) {
+		return static_cast < Alphabet < Derived, SymbolType, AlphabetType > & > ( * this );
+	}
+
+};
+
+/**
+ * Represents an notable alphabet element.
+ * @param Derived class representing datatype using this alphabet.
+ * @param SymbolType underlying type of symbols in the alphabet.
+ * @param ElementType arbirtrary type used to distinguish different alphabet elements.
+ */
+template < class Derived, class SymbolType, class ElementType >
+class AlphabetElement {
+	/**
+	 * The element.
+	 */
+	SymbolType data;
+
+public:
+	/**
+	 * Constructs an alphabet element from symbol.
+	 * @throw AlibException if symbol is not available in context of datatype where the alphabet element is used
+	 */
+	AlphabetElement ( SymbolType symbol ) : data ( std::move ( symbol ) ) {
+		valid ( data );
+
+		if ( !available ( data ) )
+			throw exception::AlibException ( "Symbol " + ( std::string ) symbol + " is not available." );
+	}
+
+	/**
+	 * Changes the alphabet element.
+	 * @param new value of the symbol element
+	 * @throw AlibException if the new symbol is not available in context of datatype instance using the alphabet
+	 */
+	bool set ( SymbolType symbol ) {
+		valid ( symbol );
+
+		if ( !available ( symbol ) ) {
+			throw exception::AlibException ( "Symbol " + ( std::string ) symbol + " is used." );
+		} else {
+			bool res = data == symbol;
+			data = std::move ( symbol );
+			return res;
+		}
+	}
+
+	/**
+	 * Returns the current alphabet element of ElementType.
+	 * @return the notable symbol from the alphabet
+	 */
+	const SymbolType & get ( ) const {
+		return data;
+	}
+
+	/**
+	 * Checks whether a concrete symbol is available in context of the datatype instance using this alphabet
+	 *
+	 * To be implemented by all template instantiations explicitly
+	 *
+	 * @param symbol symbol to check
+	 * @return true if symbol is available
+	 *         false if symbol is not available
+	 */
+	bool available ( const SymbolType & symbol ) const;
+
+	/**
+	 * Checks whether a concrete symbol is valid in context of the datatype instance using this alphabet
+	 *
+	 * To be implemented by all template instantiations explicitly
+	 *
+	 * @param symbol symbol to check
+	 * @throw AlibException if the symbol in any way invalid
+	 */
+	void valid ( const SymbolType & symbol ) const;
+};
+
+/**
+ * Auxilary class packing multiple alphabet elements.
+ */
+template < class Derived, class SymbolType, class ... AlphabetElementTypes >
+class AlphabetElementPack;
+
+/**
+ * Auxilary class packing single alphabet element.
+ */
+template < class Derived, class SymbolType, class AlphabetElementType1 >
+class AlphabetElementPack < Derived, SymbolType, AlphabetElementType1 > : public AlphabetElement < Derived, SymbolType, AlphabetElementType1 > {
+public:
+	/**
+	 * Construct an alphabet element pack from single alphabet element.
+	 */
+	AlphabetElementPack ( SymbolType first ) : AlphabetElement < Derived, SymbolType, AlphabetElementType1 > ( std::move ( first ) ) {
+	}
+
+};
+
+/**
+ * Auxilary class packing two alphabet elements.
+ */
+template < class Derived, class SymbolType, class AlphabetElementType1, class AlphabetElementType2 >
+class AlphabetElementPack < Derived, SymbolType, AlphabetElementType1, AlphabetElementType2 > : public AlphabetElement < Derived, SymbolType, AlphabetElementType1 >, public AlphabetElement < Derived, SymbolType, AlphabetElementType2 > {
+public:
+	/**
+	 * Construct an alphabet element pack from two alphabet elements.
+	 */
+	AlphabetElementPack ( SymbolType first, SymbolType second ) : AlphabetElement < Derived, SymbolType, AlphabetElementType1 > ( std::move ( first ) ), AlphabetElement < Derived, SymbolType, AlphabetElementType2 > ( std::move ( second ) ) {
+	}
+
+};
+
+/**
+ * Auxilary class allowing simple access to the alphabet elements.
+ */
+template < class Derived, class SymbolType, class ... AlphabetElementTypes >
+class AlphabetElements : public AlphabetElementPack < Derived, SymbolType, AlphabetElementTypes ... > {
+public:
+	/**
+	 * Reuse constructor of the base class.
+	 */
+	using AlphabetElementPack < Derived, SymbolType, AlphabetElementTypes ... >::AlphabetElementPack;
+
+	/**
+	 * Allow acces to subalphabet element using its type.
+	 * @param AlphabetElementType alphabet type used to distinguish different sub alphabet elements
+	 * @return subalphabet element
+	 */
+	template < class AlphabetElementType >
+	const AlphabetElement < Derived, SymbolType, AlphabetElementType > & getAlphabetElement ( ) const {
+		return static_cast < const AlphabetElement < Derived, SymbolType, AlphabetElementType > & > ( * this );
+	}
+
+	/**
+	 * Allow acces to subalphabet element using its type.
+	 * @param AlphabetElementType alphabet type used to distinguish different sub alphabet elements
+	 * @return subalphabet element
+	 */
+	template < class AlphabetElementType >
+	AlphabetElement < Derived, SymbolType, AlphabetElementType > & getAlphabetElement ( ) {
+		return static_cast < AlphabetElement < Derived, SymbolType, AlphabetElementType > & > ( * this );
+	}
+
+};
+
+} /* namespace alphabet */
+
+#endif /* ALPHABET_HPP_ */
diff --git a/alib2data/test-src/alphabet/AlphabetTest.cpp b/alib2data/test-src/alphabet/AlphabetTest.cpp
new file mode 100644
index 0000000000..77300283cb
--- /dev/null
+++ b/alib2data/test-src/alphabet/AlphabetTest.cpp
@@ -0,0 +1,120 @@
+#include "AlphabetTest.h"
+#include <alphabet/Alphabet.hpp>
+
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( AlphabetTest, "alphabet" );
+CPPUNIT_TEST_SUITE_REGISTRATION ( AlphabetTest );
+
+struct GeneralAlphabet {
+};
+
+struct NonlinearAlphabet {
+};
+
+struct SubtreeWildcard {
+};
+
+class A : public alphabet::Alphabets < A, std::string, GeneralAlphabet, NonlinearAlphabet >, public alphabet::AlphabetElements < A, std::string, SubtreeWildcard > {
+public:
+	A ( std::string string ) : Alphabets < A, std::string, GeneralAlphabet, NonlinearAlphabet > ( { string }, { } ), AlphabetElements < A, std::string, SubtreeWildcard > ( string ) {
+	}
+};
+
+namespace alphabet {
+
+template < >
+bool A::Alphabet < A, std::string, GeneralAlphabet >::used ( const std::string & string ) const {
+	return static_cast < const A * > ( this )->getAlphabet < NonlinearAlphabet > ( ).get ( ).count ( string ) || static_cast < const A * > ( this )->getAlphabetElement < SubtreeWildcard > ( ).get ( ) == string;
+}
+
+template < >
+bool A::Alphabet < A, std::string, NonlinearAlphabet >::used ( const std::string & ) const {
+	return false;
+}
+
+template < >
+bool A::Alphabet < A, std::string, GeneralAlphabet >::available ( const std::string & ) const {
+	return true;
+}
+
+template < >
+bool A::Alphabet < A, std::string, NonlinearAlphabet >::available ( const std::string & string ) const {
+	return static_cast < const A * > ( this )->getAlphabet < GeneralAlphabet > ( ).get ( ).count ( string );
+}
+
+template < >
+bool A::AlphabetElement < A, std::string, SubtreeWildcard >::available ( const std::string & string ) const {
+	return static_cast < const A * > ( this )->getAlphabet < GeneralAlphabet > ( ).get ( ).count ( string );
+}
+
+template < >
+void A::Alphabet < A, std::string, GeneralAlphabet >::valid ( const std::string & ) const {
+}
+
+template < >
+void A::Alphabet < A, std::string, NonlinearAlphabet >::valid ( const std::string & ) const {
+}
+
+template < >
+void A::AlphabetElement < A, std::string, SubtreeWildcard >::valid ( const std::string & ) const {
+}
+
+}
+
+class B : public alphabet::Alphabets < B, std::string, GeneralAlphabet, NonlinearAlphabet > {
+};
+
+namespace alphabet {
+
+template < >
+bool B::Alphabet < B, std::string, GeneralAlphabet >::used ( const std::string & ) const {
+	return false;
+}
+
+template < >
+bool B::Alphabet < B, std::string, NonlinearAlphabet >::used ( const std::string & ) const {
+	return false;
+}
+
+template < >
+bool B::Alphabet < B, std::string, GeneralAlphabet >::available ( const std::string & ) const {
+	return true;
+}
+
+template < >
+bool B::Alphabet < B, std::string, NonlinearAlphabet >::available ( const std::string & ) const {
+	return true;
+}
+
+template < >
+void B::Alphabet < B, std::string, GeneralAlphabet >::valid ( const std::string & ) const {
+}
+
+template < >
+void B::Alphabet < B, std::string, NonlinearAlphabet >::valid ( const std::string & ) const {
+}
+
+}
+
+void AlphabetTest::setUp ( ) {
+}
+
+void AlphabetTest::tearDown ( ) {
+}
+
+void AlphabetTest::testAdd ( ) {
+	A tmp ( "2" );
+
+	CPPUNIT_ASSERT_THROW ( tmp.getAlphabet < NonlinearAlphabet > ( ).add ( "1" ), exception::AlibException );
+	tmp.getAlphabet < GeneralAlphabet > ( ).add ( "1" );
+	tmp.getAlphabet < NonlinearAlphabet > ( ).add ( "1" );
+}
+
+void AlphabetTest::testRemove ( ) {
+	A tmp ( "2" );
+
+	tmp.getAlphabet < GeneralAlphabet > ( ).add ( "1" );
+	tmp.getAlphabet < NonlinearAlphabet > ( ).add ( "1" );
+	CPPUNIT_ASSERT_THROW ( tmp.getAlphabet < GeneralAlphabet > ( ).remove ( "1" ), exception::AlibException );
+	tmp.getAlphabet < NonlinearAlphabet > ( ).remove ( "1" );
+	tmp.getAlphabet < GeneralAlphabet > ( ).remove ( "1" );
+}
diff --git a/alib2data/test-src/alphabet/AlphabetTest.h b/alib2data/test-src/alphabet/AlphabetTest.h
new file mode 100644
index 0000000000..d42a0cd132
--- /dev/null
+++ b/alib2data/test-src/alphabet/AlphabetTest.h
@@ -0,0 +1,20 @@
+#ifndef ALPHABET_TEST_H_
+#define ALPHABET_TEST_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class AlphabetTest : public CppUnit::TestFixture {
+	CPPUNIT_TEST_SUITE ( AlphabetTest );
+	CPPUNIT_TEST ( testAdd );
+	CPPUNIT_TEST ( testRemove );
+	CPPUNIT_TEST_SUITE_END ( );
+
+public:
+	void setUp ( );
+	void tearDown ( );
+
+	void testAdd ( );
+	void testRemove ( );
+};
+
+#endif // ALPHABET_TEST_H_
-- 
GitLab