<commit_before>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/unique_ptr.hpp>
#include <memory>

namespace agency
{
namespace detail
{

template<class T, class Alloc = std::allocator<T>>
class boxed_value
{
  public:
    using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value()))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args... args)
      : data_(agency::detail::allocate_unique<T>(allocator_type(), std::forward<Args>(args)...))
    {}

    __AGENCY_ANNOTATION
    boxed_value& operator=(const boxed_value& other)
    {
      value() = other.value();
      return *this;
    }

    __AGENCY_ANNOTATION
    boxed_value& operator=(boxed_value&& other)
    {
      value() = std::move(other.value());
      return *this;
    }

    __AGENCY_ANNOTATION
    value_type& value() &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    value_type&& value() &&
    {
      return std::move(*data_);
    }

    __AGENCY_ANNOTATION
    const value_type&& value() const &&
    {
      return std::move(*data_);
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    agency::detail::unique_ptr<T,agency::detail::deleter<allocator_type>> data_;
};

// when the allocator is std::allocator<T>, we can just put this on the stack
template<class T, class OtherT>
class boxed_value<T,std::allocator<OtherT>>
{
  public:
    using allocator_type = std::allocator<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value_))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args&&... args)
      : value_(std::forward<Args>(args)...)
    {}

    __AGENCY_ANNOTATION
    value_type& value()
    {
      return value_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const
    {
      return value_;
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    value_type value_;
};

template<class T, class Alloc, class... Args>
__AGENCY_ANNOTATION
boxed_value<T,Alloc> allocate_boxed(const Alloc&, Args&&... args)
{
  return boxed_value<T,Alloc>(std::forward<Args>(args)...);
}

} // end detail
} // end agency

<commit_msg>Implement small object optimization for boxed_value<commit_after>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/unique_ptr.hpp>
#include <agency/detail/tuple.hpp>
#include <memory>
#include <type_traits>

namespace agency
{
namespace detail
{

namespace boxed_value_detail
{

template<class T, class Alloc>
struct use_small_object_optimization : disjunction<
  std::is_same<Alloc,std::allocator<T>>,
  std::is_empty<T>,
  is_empty_tuple<T>
>
{};

} // end boxed_value_detail

template<class T, class Alloc = std::allocator<T>,
         bool use_optimization = boxed_value_detail::use_small_object_optimization<T,Alloc>::value>
class boxed_value : private std::allocator_traits<Alloc>::template rebind_alloc<T>
{
  public:
    using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value()))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args... args)
      : data_(agency::detail::allocate_unique<T>(get_allocator(), std::forward<Args>(args)...))
    {}

    __AGENCY_ANNOTATION
    boxed_value& operator=(const boxed_value& other)
    {
      value() = other.value();
      return *this;
    }

    __AGENCY_ANNOTATION
    boxed_value& operator=(boxed_value&& other)
    {
      value() = std::move(other.value());
      return *this;
    }

    __AGENCY_ANNOTATION
    value_type& value() &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    value_type&& value() &&
    {
      return std::move(*data_);
    }

    __AGENCY_ANNOTATION
    const value_type&& value() const &&
    {
      return std::move(*data_);
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    __AGENCY_ANNOTATION
    allocator_type& get_allocator()
    {
      return *this;
    }

    agency::detail::unique_ptr<T,agency::detail::deleter<allocator_type>> data_;
};

// when using the optimization, we put the object on the stack
template<class T, class Alloc>
class boxed_value<T,Alloc,true>
{
  public:
    using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value_))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args&&... args)
      : value_(std::forward<Args>(args)...)
    {}

    __AGENCY_ANNOTATION
    value_type& value()
    {
      return value_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const
    {
      return value_;
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    value_type value_;
};

template<class T, class Alloc, class... Args>
__AGENCY_ANNOTATION
boxed_value<T,Alloc> allocate_boxed(const Alloc&, Args&&... args)
{
  return boxed_value<T,Alloc>(std::forward<Args>(args)...);
}

} // end detail
} // end agency

<|endoftext|>


<commit_before>#include "VCardParser.h"
#include <assert.h>
#include <QIODevice>
#include <QByteArray>
#include <QDebug>
#include "Exceptions.h"
#include "Contact.h"

/** Provides the actual parsing implementation. */
class VCardParserImpl
{
public:
	/** Creates a new parser instance and binds it to the specified data source and destination contact book. */
	VCardParserImpl(QIODevice & a_Source, ContactBookPtr a_Dest):
		m_Source(a_Source),
		m_Dest(a_Dest),
		m_State(psIdle),
		m_CurrentLineNum(0)
	{
	}

	/** Parses the source data from m_Source into the bound destination contact book m_Dest.
	Throws an EException descendant on error. Note that m_Dest may still be filled with some contacts
	that parsed successfully. */
	void parse()
	{
		// Parse line-by-line, unwrap the lines here:
		QByteArray acc;  // Accumulator for the current line
		while (!m_Source.atEnd())
		{
			QByteArray cur = m_Source.readLine();
			if (
				!cur.isEmpty() &&
				(
					(cur.at(0) == 0x20) ||  // Continuation by a SP
					(cur.at(0) == 0x09) ||  // Continuation by a HT
					!cur.contains(':')      // Some bad serializers don't fold the lines properly, continuations are made without the leading space (LG G4)
				)
			)
			{
				// This was a folded line, append it to the accumulator:
				cur.remove(0, 1);
				acc.append(cur);
			}
			else
			{
				// This is a (start of a) new line, process the accumulator and store the new line in it:
				if (!acc.isEmpty())
				{
					processLine(acc);
				}
				std::swap(acc, cur);
			}
		}
		// Process the last line:
		if (!acc.isEmpty())
		{
			processLine(acc);
		}
	}

protected:

	/** The state of the outer state-machine, checking the sentences' sequencing (begin, version, <data>, end). */
	enum State
	{
		psIdle,        //< The parser has no current contact, it expects a new "BEGIN:VCARD" sentence
		psBeginVCard,  //< The parser has just read the "BEGIN:VCARD" line, expects a "VERSION" sentence
		psContact,     //< The parser is reading individual contact property sentence
	} m_State;

	/** The source data provider. */
	QIODevice & m_Source;

	/** The contact book into which the data is to be written. */
	ContactBookPtr m_Dest;

	/** The current contact being parsed.
	Only valid in the psContact state. */
	ContactPtr m_CurrentContact;

	/** The number of the line currently being processed (for error reporting). */
	int m_CurrentLineNum;

	/** Parses the given single (unfolded) line. */
	void processLine(const QByteArray & a_Line)
	{
		m_CurrentLineNum += 1;
		if (a_Line.isEmpty() || (a_Line == "\n"))
		{
			return;
		}
		try
		{
			auto sentence = breakUpSentence(a_Line);
			switch (m_State)
			{
				case psIdle:       processSentenceIdle(sentence);       break;
				case psBeginVCard: processSentenceBeginVCard(sentence); break;
				case psContact:    processSentenceContact(sentence);    break;
			}
		}
		catch (const EParseError & exc)
		{
			qWarning() << QString::fromUtf8("Cannot parse VCARD, line %1: %2. The line contents: \"%3\"")
				.arg(m_CurrentLineNum)
				.arg(QString::fromStdString(exc.m_Message))
				.arg(QString::fromStdString(a_Line.toStdString()));
			throw;
		}
	}

	/** Breaks the specified single (unfolded) line into the contact sentence representation. */
	Contact::Sentence breakUpSentence(const QByteArray & a_Line)
	{
		Contact::Sentence res;

		// The state of the inner state-machine, parsing a single sentence.
		// Each sentence has a basic structure of "[group.]key[;param1;param2]=value"
		enum
		{
			ssBegin,             //< The parser is reading the beginning of the sentence (group or key)
			ssKey,               //< The parser is reading the key (the group was present)
			ssParamName,         //< The parser is reading the param name
			ssParamValue,        //< The parser is reading the param value
			ssParamValueDQuote,  //< The parser is reading the param value and is inside a dquote
			ssParamValueEnd,     //< The parser has just finished the DQuote of a param value
		} sentenceState = ssBegin;

		auto len = a_Line.length();
		assert(len > 0);
		if (a_Line.at(len - 1) == '\n')
		{
			assert(len > 1);
			len -= 1;
		}
		int last = 0;
		QByteArray currentParamName, currentParamValue;
		for (auto i = 0; i < len; ++i)
		{
			auto ch = a_Line.at(i);
			switch (sentenceState)
			{
				case ssBegin:
				{
					if (ch == '.')
					{
						res.m_Group = a_Line.mid(0, i - 1);
						last = i + 1;
						sentenceState = ssKey;
						continue;
					}
					// fallthrough
				}  // case ssBegin

				case ssKey:
				{
					if (ch == ';')
					{
						if (last == i)
						{
							throw EParseError(__FILE__, __LINE__, "An empty key is not allowed");
						}
						res.m_Key = a_Line.mid(last, i - last).toLower();
						last = i + 1;
						sentenceState = ssParamName;
						continue;
					}
					if (ch == ':')
					{
						if (last == i)
						{
							throw EParseError(__FILE__, __LINE__, "An empty key is not allowed");
						}
						res.m_Key = a_Line.mid(last, i - last).toLower();
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					if (ch == '.')
					{
						throw EParseError(__FILE__, __LINE__, "A group has already been parsed, cannot add another one.");
					}
					break;
				}  // case ssKey

				case ssParamName:
				{
					if (ch == '=')
					{
						if (i == last)
						{
							throw EParseError(__FILE__, __LINE__, "A parameter with no name is not allowed");
						}
						currentParamName = a_Line.mid(last, i - last).toLower();
						last = i + 1;
						currentParamValue.clear();
						sentenceState = ssParamValue;
						continue;
					}
					if (ch == ';')
					{
						// Value-less parameter with another parameter following ("TEL;CELL;OTHER:...")
						res.m_Params.emplace_back(currentParamName, QByteArray());
						last = i + 1;
						currentParamValue.clear();
						continue;
					}
					if (ch == ':')
					{
						// Value-less parameter ending the params ("TEL;CELL:...")
						res.m_Params.emplace_back(currentParamName, QByteArray());
						last = i + 1;
						last = i + 1;
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					break;
				}  // case ssParamName

				case ssParamValue:
				{
					if (ch == '"')
					{
						if (i > last)
						{
							throw EParseError(__FILE__, __LINE__, "Param value double-quoting is wrong");
						}
						last = i + 1;
					}
					if (ch == ',')
					{
						res.m_Params.emplace_back(currentParamName, a_Line.mid(last, i - last));
						last = i + 1;
						continue;
					}
					if (ch == ':')
					{
						res.m_Params.emplace_back(currentParamName, a_Line.mid(last, i - last));
						last = i + 1;
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					break;
				}  // case ssParamValue

				case ssParamValueDQuote:
				{
					if (ch == '"')
					{
						res.m_Params.emplace_back(currentParamName, std::move(currentParamValue));
						last = i + 1;
						sentenceState = ssParamValueEnd;
						continue;
					}
					if (ch == '\\')
					{
						// Skip the escape
						continue;
					}
					else
					{
						currentParamValue.append(ch);
					}
					break;
				}  // case ssParamValueDQuote

				case ssParamValueEnd:
				{
					if (ch == ',')
					{
						last = i + 1;
						currentParamValue.clear();
						sentenceState = ssParamValue;
					}
					if (ch == ':')
					{
						res.m_Params.emplace_back(currentParamName, a_Line.mid(last, i - last));
						last = i + 1;
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					throw EParseError(__FILE__, __LINE__, "An extra character following a param value double-quote");
				}  // case ssParamValueEnd
			}
		}  // for i - a_Line[]

		throw EParseError(__FILE__, __LINE__, "Incomplete sentence");
	}

	/** Processes the given sentence in the psIdle parser state. */
	void processSentenceIdle(const Contact::Sentence & a_Sentence)
	{
		// The only valid line in this context is the "BEGIN:VCARD" line.
		// Any other line will cause an error throw
		if (
			!a_Sentence.m_Group.isEmpty()
		)
		{
			throw EParseError(__FILE__, __LINE__, "Expected a BEGIN:VCARD sentence, got a different sentence");
		}
		m_State = psBeginVCard;
	}

	/** Parses the given single sentence in the psBeginVCard parser state. */
	void processSentenceBeginVCard(const Contact::Sentence & a_Sentence)
	{
		// The only valid sentence in this context is the "VERSION:X" line.
		if (
			!a_Sentence.m_Group.isEmpty() ||
			(a_Sentence.m_Key != "version") ||
			!a_Sentence.m_Params.empty()
		)
		{
			throw EParseError(__FILE__, __LINE__, "Expected a VERSION sentence, got a different sentence");
		}
		if (a_Sentence.m_Value.toFloat() == 0)
		{
			throw EParseError(__FILE__, __LINE__, "The VERSION sentence has an invalid value.");
		}

		m_CurrentContact.reset(new Contact);
		m_State = psContact;
	}

	/** Parses the given single (unfolded) line in the psContact parser state. */
	void processSentenceContact(const Contact::Sentence & a_Sentence)
	{
		// If the sentence is "END:VCARD", terminate the current contact:
		if (
			a_Sentence.m_Group.isEmpty() &&
			(a_Sentence.m_Key == "end") &&
			a_Sentence.m_Params.empty() &&
			(a_Sentence.m_Value.toLower() == "vcard")
		)
		{
			if (m_CurrentContact != nullptr)
			{
				m_Dest->addContact(m_CurrentContact);
			}
			m_CurrentContact.reset();
			m_State = psIdle;
			return;
		}

		// Add the sentence to the current contact:
		m_CurrentContact->addSentence(a_Sentence);
	}
};

void VCardParser::parse(QIODevice & a_Source, ContactBookPtr a_Dest)
{
	VCardParserImpl impl(a_Source, a_Dest);
	impl.parse();
}

std::vector<std::vector<QByteArray>> VCardParser::breakValueIntoComponents(const QByteArray & a_Value)
{
	std::vector<std::vector<QByteArray>> res;
	res.push_back({});
	auto * curComponent = &res.back();
	curComponent->push_back({});
	auto * curValue = &curComponent->back();
	auto len = a_Value.length();
	for (int i = 0; i < len; ++i)
	{
		auto ch = a_Value.at(i);
		switch (ch)
		{
			case ';':
			{
				// Start a new component:
				res.push_back({});
				curComponent = &res.back();
				curComponent->push_back({});
				curValue = &curComponent->back();
				break;
			}  // case ';'

			case ',':
			{
				// Start a new value:
				curComponent->push_back({});
				curValue = &curComponent->back();
				break;
			}

			case '\\':
			{
				// Skip the escape char and push the next char directly into the current value:
				i = 1 + 1;
				curValue->append(a_Value.at(i));
				break;
			}

			default:
			{
				curValue->append(ch);
				break;
			}
		}  // switch (ch)
	}  // for i - a_Value[]

	return res;
}

<commit_msg>Fixed Linux compilation warnings.<commit_after>#include "VCardParser.h"
#include <assert.h>
#include <QIODevice>
#include <QByteArray>
#include <QDebug>
#include "Exceptions.h"
#include "Contact.h"

/** Provides the actual parsing implementation. */
class VCardParserImpl
{
public:
	/** Creates a new parser instance and binds it to the specified data source and destination contact book. */
	VCardParserImpl(QIODevice & a_Source, ContactBookPtr a_Dest):
		m_State(psIdle),
		m_Source(a_Source),
		m_Dest(a_Dest),
		m_CurrentLineNum(0)
	{
	}

	/** Parses the source data from m_Source into the bound destination contact book m_Dest.
	Throws an EException descendant on error. Note that m_Dest may still be filled with some contacts
	that parsed successfully. */
	void parse()
	{
		// Parse line-by-line, unwrap the lines here:
		QByteArray acc;  // Accumulator for the current line
		while (!m_Source.atEnd())
		{
			QByteArray cur = m_Source.readLine();
			if (
				!cur.isEmpty() &&
				(
					(cur.at(0) == 0x20) ||  // Continuation by a SP
					(cur.at(0) == 0x09) ||  // Continuation by a HT
					!cur.contains(':')      // Some bad serializers don't fold the lines properly, continuations are made without the leading space (LG G4)
				)
			)
			{
				// This was a folded line, append it to the accumulator:
				cur.remove(0, 1);
				acc.append(cur);
			}
			else
			{
				// This is a (start of a) new line, process the accumulator and store the new line in it:
				if (!acc.isEmpty())
				{
					processLine(acc);
				}
				std::swap(acc, cur);
			}
		}
		// Process the last line:
		if (!acc.isEmpty())
		{
			processLine(acc);
		}
	}

protected:

	/** The state of the outer state-machine, checking the sentences' sequencing (begin, version, <data>, end). */
	enum State
	{
		psIdle,        //< The parser has no current contact, it expects a new "BEGIN:VCARD" sentence
		psBeginVCard,  //< The parser has just read the "BEGIN:VCARD" line, expects a "VERSION" sentence
		psContact,     //< The parser is reading individual contact property sentence
	} m_State;

	/** The source data provider. */
	QIODevice & m_Source;

	/** The contact book into which the data is to be written. */
	ContactBookPtr m_Dest;

	/** The current contact being parsed.
	Only valid in the psContact state. */
	ContactPtr m_CurrentContact;

	/** The number of the line currently being processed (for error reporting). */
	int m_CurrentLineNum;

	/** Parses the given single (unfolded) line. */
	void processLine(const QByteArray & a_Line)
	{
		m_CurrentLineNum += 1;
		if (a_Line.isEmpty() || (a_Line == "\n"))
		{
			return;
		}
		try
		{
			auto sentence = breakUpSentence(a_Line);
			switch (m_State)
			{
				case psIdle:       processSentenceIdle(sentence);       break;
				case psBeginVCard: processSentenceBeginVCard(sentence); break;
				case psContact:    processSentenceContact(sentence);    break;
			}
		}
		catch (const EParseError & exc)
		{
			qWarning() << QString::fromUtf8("Cannot parse VCARD, line %1: %2. The line contents: \"%3\"")
				.arg(m_CurrentLineNum)
				.arg(QString::fromStdString(exc.m_Message))
				.arg(QString::fromUtf8(a_Line));
			throw;
		}
	}

	/** Breaks the specified single (unfolded) line into the contact sentence representation. */
	Contact::Sentence breakUpSentence(const QByteArray & a_Line)
	{
		Contact::Sentence res;

		// The state of the inner state-machine, parsing a single sentence.
		// Each sentence has a basic structure of "[group.]key[;param1;param2]=value"
		enum
		{
			ssBegin,             //< The parser is reading the beginning of the sentence (group or key)
			ssKey,               //< The parser is reading the key (the group was present)
			ssParamName,         //< The parser is reading the param name
			ssParamValue,        //< The parser is reading the param value
			ssParamValueDQuote,  //< The parser is reading the param value and is inside a dquote
			ssParamValueEnd,     //< The parser has just finished the DQuote of a param value
		} sentenceState = ssBegin;

		auto len = a_Line.length();
		assert(len > 0);
		if (a_Line.at(len - 1) == '\n')
		{
			assert(len > 1);
			len -= 1;
		}
		int last = 0;
		QByteArray currentParamName, currentParamValue;
		for (auto i = 0; i < len; ++i)
		{
			auto ch = a_Line.at(i);
			switch (sentenceState)
			{
				case ssBegin:
				{
					if (ch == '.')
					{
						res.m_Group = a_Line.mid(0, i - 1);
						last = i + 1;
						sentenceState = ssKey;
						continue;
					}
					// fallthrough
				}  // case ssBegin

				case ssKey:
				{
					if (ch == ';')
					{
						if (last == i)
						{
							throw EParseError(__FILE__, __LINE__, "An empty key is not allowed");
						}
						res.m_Key = a_Line.mid(last, i - last).toLower();
						last = i + 1;
						sentenceState = ssParamName;
						continue;
					}
					if (ch == ':')
					{
						if (last == i)
						{
							throw EParseError(__FILE__, __LINE__, "An empty key is not allowed");
						}
						res.m_Key = a_Line.mid(last, i - last).toLower();
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					if (ch == '.')
					{
						throw EParseError(__FILE__, __LINE__, "A group has already been parsed, cannot add another one.");
					}
					break;
				}  // case ssKey

				case ssParamName:
				{
					if (ch == '=')
					{
						if (i == last)
						{
							throw EParseError(__FILE__, __LINE__, "A parameter with no name is not allowed");
						}
						currentParamName = a_Line.mid(last, i - last).toLower();
						last = i + 1;
						currentParamValue.clear();
						sentenceState = ssParamValue;
						continue;
					}
					if (ch == ';')
					{
						// Value-less parameter with another parameter following ("TEL;CELL;OTHER:...")
						res.m_Params.emplace_back(currentParamName, QByteArray());
						last = i + 1;
						currentParamValue.clear();
						continue;
					}
					if (ch == ':')
					{
						// Value-less parameter ending the params ("TEL;CELL:...")
						res.m_Params.emplace_back(currentParamName, QByteArray());
						last = i + 1;
						last = i + 1;
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					break;
				}  // case ssParamName

				case ssParamValue:
				{
					if (ch == '"')
					{
						if (i > last)
						{
							throw EParseError(__FILE__, __LINE__, "Param value double-quoting is wrong");
						}
						last = i + 1;
					}
					if (ch == ',')
					{
						res.m_Params.emplace_back(currentParamName, a_Line.mid(last, i - last));
						last = i + 1;
						continue;
					}
					if (ch == ':')
					{
						res.m_Params.emplace_back(currentParamName, a_Line.mid(last, i - last));
						last = i + 1;
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					break;
				}  // case ssParamValue

				case ssParamValueDQuote:
				{
					if (ch == '"')
					{
						res.m_Params.emplace_back(currentParamName, std::move(currentParamValue));
						last = i + 1;
						sentenceState = ssParamValueEnd;
						continue;
					}
					if (ch == '\\')
					{
						// Skip the escape
						continue;
					}
					else
					{
						currentParamValue.append(ch);
					}
					break;
				}  // case ssParamValueDQuote

				case ssParamValueEnd:
				{
					if (ch == ',')
					{
						last = i + 1;
						currentParamValue.clear();
						sentenceState = ssParamValue;
					}
					if (ch == ':')
					{
						res.m_Params.emplace_back(currentParamName, a_Line.mid(last, i - last));
						last = i + 1;
						res.m_Value = a_Line.mid(i + 1, len - i - 1);
						return res;
					}
					throw EParseError(__FILE__, __LINE__, "An extra character following a param value double-quote");
				}  // case ssParamValueEnd
			}
		}  // for i - a_Line[]

		throw EParseError(__FILE__, __LINE__, "Incomplete sentence");
	}

	/** Processes the given sentence in the psIdle parser state. */
	void processSentenceIdle(const Contact::Sentence & a_Sentence)
	{
		// The only valid line in this context is the "BEGIN:VCARD" line.
		// Any other line will cause an error throw
		if (
			!a_Sentence.m_Group.isEmpty()
		)
		{
			throw EParseError(__FILE__, __LINE__, "Expected a BEGIN:VCARD sentence, got a different sentence");
		}
		m_State = psBeginVCard;
	}

	/** Parses the given single sentence in the psBeginVCard parser state. */
	void processSentenceBeginVCard(const Contact::Sentence & a_Sentence)
	{
		// The only valid sentence in this context is the "VERSION:X" line.
		if (
			!a_Sentence.m_Group.isEmpty() ||
			(a_Sentence.m_Key != "version") ||
			!a_Sentence.m_Params.empty()
		)
		{
			throw EParseError(__FILE__, __LINE__, "Expected a VERSION sentence, got a different sentence");
		}
		if (a_Sentence.m_Value.toFloat() == 0)
		{
			throw EParseError(__FILE__, __LINE__, "The VERSION sentence has an invalid value.");
		}

		m_CurrentContact.reset(new Contact);
		m_State = psContact;
	}

	/** Parses the given single (unfolded) line in the psContact parser state. */
	void processSentenceContact(const Contact::Sentence & a_Sentence)
	{
		// If the sentence is "END:VCARD", terminate the current contact:
		if (
			a_Sentence.m_Group.isEmpty() &&
			(a_Sentence.m_Key == "end") &&
			a_Sentence.m_Params.empty() &&
			(a_Sentence.m_Value.toLower() == "vcard")
		)
		{
			if (m_CurrentContact != nullptr)
			{
				m_Dest->addContact(m_CurrentContact);
			}
			m_CurrentContact.reset();
			m_State = psIdle;
			return;
		}

		// Add the sentence to the current contact:
		m_CurrentContact->addSentence(a_Sentence);
	}
};

void VCardParser::parse(QIODevice & a_Source, ContactBookPtr a_Dest)
{
	VCardParserImpl impl(a_Source, a_Dest);
	impl.parse();
}

std::vector<std::vector<QByteArray>> VCardParser::breakValueIntoComponents(const QByteArray & a_Value)
{
	std::vector<std::vector<QByteArray>> res;
	res.push_back({});
	auto * curComponent = &res.back();
	curComponent->push_back({});
	auto * curValue = &curComponent->back();
	auto len = a_Value.length();
	for (int i = 0; i < len; ++i)
	{
		auto ch = a_Value.at(i);
		switch (ch)
		{
			case ';':
			{
				// Start a new component:
				res.push_back({});
				curComponent = &res.back();
				curComponent->push_back({});
				curValue = &curComponent->back();
				break;
			}  // case ';'

			case ',':
			{
				// Start a new value:
				curComponent->push_back({});
				curValue = &curComponent->back();
				break;
			}

			case '\\':
			{
				// Skip the escape char and push the next char directly into the current value:
				i = 1 + 1;
				curValue->append(a_Value.at(i));
				break;
			}

			default:
			{
				curValue->append(ch);
				break;
			}
		}  // switch (ch)
	}  // for i - a_Value[]

	return res;
}

<|endoftext|>


<commit_before>//=============================================================================
// ■ VMDE/global.hpp
//-----------------------------------------------------------------------------
//   在VMDE的内部，包容一切的头。
//   关于只有一个头：
//   我完全无法理解为什么C要采用有头文件的设计。当然这很可能是历史遗留问题，
//   但这导致了C程序员总是需要花费大量时间整理头文件，且这时间花得莫名其妙。
//   而这在其他任何语系中都不是问题：即使是采用C语法的衍生语言，也不会保留
//   这个“特性”。因此我们需要解决它。
//   采用#include管理多文件编译是最好的解决方案。在现今编译单个文件的速度有极
//   大提升的时代，一个个编译小文件却慢得多。然而这个解决方案并不能在像VMDE这
//   样的合作项目中进行，因为它会让很多已建立的条件反射、编译器、IDE日狗。
//   单一头文件也是一个可行的方案。它保留了头文件，但只有一个——这意味着所有
//   你需要编辑的头都在固定的位置，给身体和手带来了放松的空间，同时也保证编辑
//   器的标签栏（如果有的话）不会因为头文件而缩小为原来的一半。
//   当然，还有一个解决办法就是只用一个.c文件。结果：从此这个项目就没落了。
//   综上所述，我选择狗带，砍了其他所有头。
//=============================================================================

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <ctime>
#include <thread>
#include <cstdarg>
#include <cassert>

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <SOIL.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <portaudio.h>
#include <vorbis/vorbisfile.h>

#ifndef _INCLUDE_GLOBAL_H
	#define _INCLUDE_GLOBAL_H
	using namespace std;
	//-------------------------------------------------------------------------
	// ● PY Deal For ＭICR0$○F┬ Ｗindoges (ᴚ)
	//Becuase it;s Windoges,I jsut dno't want to use CORERCT ENGRISh &忠闻吔屎炉此
	//-------------------------------------------------------------------------
	#ifdef __MINGW32__
		#define EXPORTED extern "C" __declspec(dllexport)
	#else
		#define EXPORTED extern "C"
	#endif
	#ifdef __CYGWIN__
		#warning This will not work in Cygwin. Try at your own risk.
	#endif
	//-------------------------------------------------------------------------
	// ● 定义宏魔法
	//-------------------------------------------------------------------------
	// NDEBUG - 给assert用的，虽然好像这项目里没人用assert
	// 这个DEBUG在make的时候加（make debug）。
	#ifdef DEBUG
		#define NDEBUG
	#else
		#undef NDEBUG
	#endif
	// ARRAY_SIZE - 获取定义的数组大小
	//     int a[56]; → ARRAY_SIZE(a) == 56
	#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
	// MLVN - Macro-Local Variable Name
	// 这是为了不让明文变量名被莫名其妙使用而设计的。
	//     #define TEST do { int MLVN() = 0, MLVN(another) = 0; } while(0)
	#define MLVN(name) My_Lovely_##name##___
	// NTIMES - 执行多次
	//     NTIMES(3) puts("Three or more, use a for");
	#define NTIMES(n) \
		for (unsigned short MLVN(index) = 0; MLVN(index) < (n); MLVN(index)++)
	// TWICE - 执行两次
	//     TWICE a++;
	//     TWICE { a++; b++; }
	#define TWICE NTIMES(2)
	// XE - 释放内存黑魔法
	// “X掉Exceptions”！
	//     void* m;
	//     m = malloc(1); xe(free, m);
	//     m = (void*) 0; xe(free, m);
	//     m = new float; xe(delete, m);
	//     m = new tm[4]; xe(delete[], m);
	#define XE(method, pointer) do { \
		if (pointer) { \
			method(pointer); \
			(pointer) = NULL; \
		} \
	} while (false)
	// VMDE_Dispose - 一键销毁宏魔法
	#define VMDE_Dispose(method, object) do { \
		if (object) { \
			method(object); \
			(object) = NULL; \
		} \
	} while (false)
	// DEBUG_ENVIRONMENT - 调试环境
	// 这个字符串会显示在log函数输出的开头。
	#define DEBUG_ENVIRONMENT "VMDE"
	// log - Util::log_internal的方便缩写，可以直接得到当前函数名
	//     log("%p", log);
	#define log(...) Util::log_internal(DEBUG_ENVIRONMENT, __func__, __VA_ARGS__)
	// mark - 逐行打log的偷懒大法
	#define mark log("Mark on line %d of %s", __LINE__, __FILE__)
	// error_internal
	#define error_internal(extra, ...) do { \
		log(__VA_ARGS__); \
		extra \
		exit(1); \
	} while (false)
	// error - 抛出错误并终止程序
	#define error(...) error_internal(, __VA_ARGS__)
	// errorp - error + perror
	#define errorp(...) error_internal(perror("perror()"), __VA_ARGS__)
	//-------------------------------------------------------------------------
	// ● util.cpp
	//   这个Util的意义已经远超utility。
	//-------------------------------------------------------------------------
	namespace Util {
		extern FILE* log_file;
		void init();
		void terminate();
		void log_internal(const char*, const char*, const char*, ...)
			__attribute__((format(printf, 3, 4)));
		char* read_file(const char* filename);
	}
	//-------------------------------------------------------------------------
	// ● 子文件夹中的头文件
	//-------------------------------------------------------------------------
	#include "VLib/V.hpp"
	#include "Audio/audio.hpp"
	//-------------------------------------------------------------------------
	// ● init.cpp
	//-------------------------------------------------------------------------
	EXPORTED void init_engine(int w, int h, const char* title);
	void setup_viewport();
	void init_vmde(int w, int h);
	void check_gl_error();
	//-------------------------------------------------------------------------
	// ● terminate.cpp
	//-------------------------------------------------------------------------
	EXPORTED void terminate_engine();
	//-------------------------------------------------------------------------
	// ● main.cpp
	//-------------------------------------------------------------------------
	void glfw_error_callback(int error, const char* description);
	void main_draw_start();
	void main_draw_end();
	void main_set_brightness(float b);
	extern glm::mat4 projection, view;
	//-------------------------------------------------------------------------
	// ● RenderObject.cpp
	//-------------------------------------------------------------------------
	class Object {
	public:
		virtual ~Object();
	};

	class RenderObject : public Object {
	public:
		virtual void render() = 0;
	};
	//-------------------------------------------------------------------------
	// ● resources.cpp
	//-------------------------------------------------------------------------
	namespace Res {
		struct TextureParameters {
			GLuint WRAP_MODE_S, WRAP_MODE_T;
			GLuint MIN_FILTER, MAG_FILTER;
			GLuint MIPMAP_LEVEL;
			GLuint PixelFormat, PixelType;
		};

		extern struct TextureParameters DefaultTextureParameters;
		extern struct TextureParameters LinearTextureParameters;

		class Texture : public Object {
		public:
			GLuint texture, index;
			int width, height;
			struct TextureParameters* parameter;

			Texture();
			Texture(const char* file);
			Texture(const char* file, struct TextureParameters* p);

			~Texture();
		};
	}
	//-------------------------------------------------------------------------
	// ● shaders.cpp
	//-------------------------------------------------------------------------
	class Shaders : public Object {
	public:
		#define SHADERS_SLOT_COUNT 16
		GLuint shaders[SHADERS_SLOT_COUNT];
		size_t shader_count = 0;
		GLuint program;

		GLuint UBO_matrix;
		glm::mat4 mat[3];

	public:
		Shaders();
		void add_string(GLenum type, const GLchar* source);
		void add_file(GLenum type, const char* filename);
		void link_program();
		void use();

		void set_float(const char* identifier, GLfloat value);
		void set_int(const char* identifier, GLint value);
		void set_texture(const char* identifier, Res::Texture* tex, GLuint index);

		void ProjectionView(glm::mat4 projection, glm::mat4 view);

		~Shaders();

	private:
		static void check_shader_compilation(
			GLuint shader,
			const char* msg = "shader compile error"
		);
		static void check_linkage(
			GLuint program,
			const char* msg = "link error"
		);
	};
	extern Shaders* _shaders_in_use;
	//-------------------------------------------------------------------------
	// ● VMDE
	//-------------------------------------------------------------------------
	struct VMDEState {
		bool frozen;
		float brightness;
	};

	enum GL_VER {
		GL_33,
		GL_43,
		VULKAN // Not used
	};

	struct VMDE {
		VMDEState state;
		long frame_count;
		long millisecond;
		int width, height;
		int fps;
		double frame_time;
		bool done;

		int gl_ver;
	};

	// VMDE操控的全局变量
	extern struct VMDE* VMDE;
	extern GLFWwindow* window;

	//-------------------------------------------------------------------------
	// ● State Control
	//-------------------------------------------------------------------------
	//   在OpenGL状态机外层再加一个状态管理机制，减少不必要的状态切换和不必要的draw call
	//   这样的一个状态机设计也可以更好地隔离API，为以后Vulkan做准备
	class VMStateControl {
		static struct StateMachineStruct {
			GLuint VERTEX_ARRAY;
			GLuint ELEMENT_ARRAY_BUFFER;
			GLuint ARRAY_BUFFER;
			GLuint TEXTURE_2D;
			GLuint UNIFORM_BUFFER;
			GLuint Shader_Program;
			bool TextureActivated[32]; // 32 for GL 3.X+, should be enough

			bool DEPTH_TEST;
			bool CULL_FACE;
			bool BLEND;
			GLuint PolygonMode;
		} StateMachine;

	public:
		static void ChangeVertexArray (GLuint index);
		static void ChangeElementArrayBuffer (GLuint index);
		static void ChangeArrayBuffer (GLuint index);
		static void ChangeTexture2D (GLuint index);
		static void ChangeUniformBuffer (GLuint index);
		static void ChangeShaderProgram (GLuint index);

		static void enable_cullface();
		static void disable_cullface();
		static void enable_depth_test();
		static void disable_depth_test();
		static void enable_blend();
		static void disable_blend();
		static void render_mode_wireframe();
		static void render_mode_fill();

		static void init_graphics_state ();
	};
	#define VMSC VMStateControl // 少写几个字

	//-------------------------------------------------------------------------
	// ● GDrawable
	//-------------------------------------------------------------------------
	struct Vertex {
		glm::vec3 world_position;
		glm::vec4 color;
		glm::vec2 st;
		glm::vec3 normal;
	};

	class GDrawable : public RenderObject {
	public:
		struct Data {
			Vertex* vertices;
			int vtx_c;
			GLuint* indices;
			int ind_c;
			GLuint* mat;
			int mat_c;
			GLuint MBO;
			GLuint VAO;
			GLuint VBO;
			GLuint EBO;
			glm::mat4 model;
		} data;

		void renderOnce();
		void render();
		void fbind();
		void update();
		void update_instance();
		void update_instance_alien_size();

		static inline void close_draw_node() { VMStateControl::ChangeVertexArray(0); }

		~GDrawable();

		GDrawable();
	};

	//-------------------------------------------------------------------------
	// ● Text
	//-------------------------------------------------------------------------
	class TextRenderer : public RenderObject {
	private:
		GDrawable obj;
		Res::Texture tex = Res::Texture("../Media/Font.bmp", &Res::LinearTextureParameters);
		Shaders texshader;

	public:
		enum TextDecorationType {
			NONE,
			SHADOW,
			OUTLINE,
		};
		TextRenderer();
		void BakeText(
			const char* text,
			float width, float height,
			TextDecorationType decoration
		);
		void render();
		void instanceRenderText(
			const char* text,
			glm::mat4 projection, glm::mat4 view, glm::mat4 transform,
			float width, float height, TextDecorationType decoration
		);
	};

	//-------------------------------------------------------------------------
	// ● RenderBuffer
	//-------------------------------------------------------------------------
	class RenderBuffer : public Object {
	public:
		GLuint framebuffer;
		GLuint rbo;
		Res::Texture** texture_buffer;
		int mrtcount;

		//void resize(int w, int h);

		void bind();
		static void unbind();
		static void clearColor(float r, float g, float b, float a);
		static void clearColorDepth(float r, float g, float b, float a);
		static void clearDepth();

		RenderBuffer(int w, int h, int mrt, const GLuint* type);
		void set_draw_buffers();
		~RenderBuffer();
	};

	class PostProcessingManager : public Object {
	private:
		static GDrawable* QuadScreen;

	public:
		static void init();
		static void Blit2D();
	};

#endif
<commit_msg>Fix macro errorp<commit_after>//=============================================================================
// ■ VMDE/global.hpp
//-----------------------------------------------------------------------------
//   在VMDE的内部，包容一切的头。
//   关于只有一个头：
//   我完全无法理解为什么C要采用有头文件的设计。当然这很可能是历史遗留问题，
//   但这导致了C程序员总是需要花费大量时间整理头文件，且这时间花得莫名其妙。
//   而这在其他任何语系中都不是问题：即使是采用C语法的衍生语言，也不会保留
//   这个“特性”。因此我们需要解决它。
//   采用#include管理多文件编译是最好的解决方案。在现今编译单个文件的速度有极
//   大提升的时代，一个个编译小文件却慢得多。然而这个解决方案并不能在像VMDE这
//   样的合作项目中进行，因为它会让很多已建立的条件反射、编译器、IDE日狗。
//   单一头文件也是一个可行的方案。它保留了头文件，但只有一个——这意味着所有
//   你需要编辑的头都在固定的位置，给身体和手带来了放松的空间，同时也保证编辑
//   器的标签栏（如果有的话）不会因为头文件而缩小为原来的一半。
//   当然，还有一个解决办法就是只用一个.c文件。结果：从此这个项目就没落了。
//   综上所述，我选择狗带，砍了其他所有头。
//=============================================================================

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <ctime>
#include <thread>
#include <cstdarg>
#include <cassert>

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <SOIL.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <portaudio.h>
#include <vorbis/vorbisfile.h>

#ifndef _INCLUDE_GLOBAL_H
	#define _INCLUDE_GLOBAL_H
	using namespace std;
	//-------------------------------------------------------------------------
	// ● PY Deal For ＭICR0$○F┬ Ｗindoges (ᴚ)
	//Becuase it;s Windoges,I jsut dno't want to use CORERCT ENGRISh &忠闻吔屎炉此
	//-------------------------------------------------------------------------
	#ifdef __MINGW32__
		#define EXPORTED extern "C" __declspec(dllexport)
	#else
		#define EXPORTED extern "C"
	#endif
	#ifdef __CYGWIN__
		#warning This will not work in Cygwin. Try at your own risk.
	#endif
	//-------------------------------------------------------------------------
	// ● 定义宏魔法
	//-------------------------------------------------------------------------
	// NDEBUG - 给assert用的，虽然好像这项目里没人用assert
	// 这个DEBUG在make的时候加（make debug）。
	#ifdef DEBUG
		#define NDEBUG
	#else
		#undef NDEBUG
	#endif
	// ARRAY_SIZE - 获取定义的数组大小
	//     int a[56]; → ARRAY_SIZE(a) == 56
	#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
	// MLVN - Macro-Local Variable Name
	// 这是为了不让明文变量名被莫名其妙使用而设计的。
	//     #define TEST do { int MLVN() = 0, MLVN(another) = 0; } while(0)
	#define MLVN(name) My_Lovely_##name##___
	// NTIMES - 执行多次
	//     NTIMES(3) puts("Three or more, use a for");
	#define NTIMES(n) \
		for (unsigned short MLVN(index) = 0; MLVN(index) < (n); MLVN(index)++)
	// TWICE - 执行两次
	//     TWICE a++;
	//     TWICE { a++; b++; }
	#define TWICE NTIMES(2)
	// XE - 释放内存黑魔法
	// “X掉Exceptions”！
	//     void* m;
	//     m = malloc(1); xe(free, m);
	//     m = (void*) 0; xe(free, m);
	//     m = new float; xe(delete, m);
	//     m = new tm[4]; xe(delete[], m);
	#define XE(method, pointer) do { \
		if (pointer) { \
			method(pointer); \
			(pointer) = NULL; \
		} \
	} while (false)
	// VMDE_Dispose - 一键销毁宏魔法
	#define VMDE_Dispose(method, object) do { \
		if (object) { \
			method(object); \
			(object) = NULL; \
		} \
	} while (false)
	// DEBUG_ENVIRONMENT - 调试环境
	// 这个字符串会显示在log函数输出的开头。
	#define DEBUG_ENVIRONMENT "VMDE"
	// log - Util::log_internal的方便缩写，可以直接得到当前函数名
	//     log("%p", log);
	#define log(...) Util::log_internal(DEBUG_ENVIRONMENT, __func__, __VA_ARGS__)
	// mark - 逐行打log的偷懒大法
	#define mark log("Mark on line %d of %s", __LINE__, __FILE__)
	// error_internal
	#define error_internal(extra, ...) do { \
		log(__VA_ARGS__); \
		extra \
		exit(1); \
	} while (false)
	// error - 抛出错误并终止程序
	#define error(...) error_internal(, __VA_ARGS__)
	// errorp - error + perror
	#define errorp(...) error_internal(perror("perror()");, __VA_ARGS__)
	//-------------------------------------------------------------------------
	// ● util.cpp
	//   这个Util的意义已经远超utility。
	//-------------------------------------------------------------------------
	namespace Util {
		extern FILE* log_file;
		void init();
		void terminate();
		void log_internal(const char*, const char*, const char*, ...)
			__attribute__((format(printf, 3, 4)));
		char* read_file(const char* filename);
	}
	//-------------------------------------------------------------------------
	// ● 子文件夹中的头文件
	//-------------------------------------------------------------------------
	#include "VLib/V.hpp"
	#include "Audio/audio.hpp"
	//-------------------------------------------------------------------------
	// ● init.cpp
	//-------------------------------------------------------------------------
	EXPORTED void init_engine(int w, int h, const char* title);
	void setup_viewport();
	void init_vmde(int w, int h);
	void check_gl_error();
	//-------------------------------------------------------------------------
	// ● terminate.cpp
	//-------------------------------------------------------------------------
	EXPORTED void terminate_engine();
	//-------------------------------------------------------------------------
	// ● main.cpp
	//-------------------------------------------------------------------------
	void glfw_error_callback(int error, const char* description);
	void main_draw_start();
	void main_draw_end();
	void main_set_brightness(float b);
	extern glm::mat4 projection, view;
	//-------------------------------------------------------------------------
	// ● RenderObject.cpp
	//-------------------------------------------------------------------------
	class Object {
	public:
		virtual ~Object();
	};

	class RenderObject : public Object {
	public:
		virtual void render() = 0;
	};
	//-------------------------------------------------------------------------
	// ● resources.cpp
	//-------------------------------------------------------------------------
	namespace Res {
		struct TextureParameters {
			GLuint WRAP_MODE_S, WRAP_MODE_T;
			GLuint MIN_FILTER, MAG_FILTER;
			GLuint MIPMAP_LEVEL;
			GLuint PixelFormat, PixelType;
		};

		extern struct TextureParameters DefaultTextureParameters;
		extern struct TextureParameters LinearTextureParameters;

		class Texture : public Object {
		public:
			GLuint texture, index;
			int width, height;
			struct TextureParameters* parameter;

			Texture();
			Texture(const char* file);
			Texture(const char* file, struct TextureParameters* p);

			~Texture();
		};
	}
	//-------------------------------------------------------------------------
	// ● shaders.cpp
	//-------------------------------------------------------------------------
	class Shaders : public Object {
	public:
		#define SHADERS_SLOT_COUNT 16
		GLuint shaders[SHADERS_SLOT_COUNT];
		size_t shader_count = 0;
		GLuint program;

		GLuint UBO_matrix;
		glm::mat4 mat[3];

	public:
		Shaders();
		void add_string(GLenum type, const GLchar* source);
		void add_file(GLenum type, const char* filename);
		void link_program();
		void use();

		void set_float(const char* identifier, GLfloat value);
		void set_int(const char* identifier, GLint value);
		void set_texture(const char* identifier, Res::Texture* tex, GLuint index);

		void ProjectionView(glm::mat4 projection, glm::mat4 view);

		~Shaders();

	private:
		static void check_shader_compilation(
			GLuint shader,
			const char* msg = "shader compile error"
		);
		static void check_linkage(
			GLuint program,
			const char* msg = "link error"
		);
	};
	extern Shaders* _shaders_in_use;
	//-------------------------------------------------------------------------
	// ● VMDE
	//-------------------------------------------------------------------------
	struct VMDEState {
		bool frozen;
		float brightness;
	};

	enum GL_VER {
		GL_33,
		GL_43,
		VULKAN // Not used
	};

	struct VMDE {
		VMDEState state;
		long frame_count;
		long millisecond;
		int width, height;
		int fps;
		double frame_time;
		bool done;

		int gl_ver;
	};

	// VMDE操控的全局变量
	extern struct VMDE* VMDE;
	extern GLFWwindow* window;

	//-------------------------------------------------------------------------
	// ● State Control
	//-------------------------------------------------------------------------
	//   在OpenGL状态机外层再加一个状态管理机制，减少不必要的状态切换和不必要的draw call
	//   这样的一个状态机设计也可以更好地隔离API，为以后Vulkan做准备
	class VMStateControl {
		static struct StateMachineStruct {
			GLuint VERTEX_ARRAY;
			GLuint ELEMENT_ARRAY_BUFFER;
			GLuint ARRAY_BUFFER;
			GLuint TEXTURE_2D;
			GLuint UNIFORM_BUFFER;
			GLuint Shader_Program;
			bool TextureActivated[32]; // 32 for GL 3.X+, should be enough

			bool DEPTH_TEST;
			bool CULL_FACE;
			bool BLEND;
			GLuint PolygonMode;
		} StateMachine;

	public:
		static void ChangeVertexArray (GLuint index);
		static void ChangeElementArrayBuffer (GLuint index);
		static void ChangeArrayBuffer (GLuint index);
		static void ChangeTexture2D (GLuint index);
		static void ChangeUniformBuffer (GLuint index);
		static void ChangeShaderProgram (GLuint index);

		static void enable_cullface();
		static void disable_cullface();
		static void enable_depth_test();
		static void disable_depth_test();
		static void enable_blend();
		static void disable_blend();
		static void render_mode_wireframe();
		static void render_mode_fill();

		static void init_graphics_state ();
	};
	#define VMSC VMStateControl // 少写几个字

	//-------------------------------------------------------------------------
	// ● GDrawable
	//-------------------------------------------------------------------------
	struct Vertex {
		glm::vec3 world_position;
		glm::vec4 color;
		glm::vec2 st;
		glm::vec3 normal;
	};

	class GDrawable : public RenderObject {
	public:
		struct Data {
			Vertex* vertices;
			int vtx_c;
			GLuint* indices;
			int ind_c;
			GLuint* mat;
			int mat_c;
			GLuint MBO;
			GLuint VAO;
			GLuint VBO;
			GLuint EBO;
			glm::mat4 model;
		} data;

		void renderOnce();
		void render();
		void fbind();
		void update();
		void update_instance();
		void update_instance_alien_size();

		static inline void close_draw_node() { VMStateControl::ChangeVertexArray(0); }

		~GDrawable();

		GDrawable();
	};

	//-------------------------------------------------------------------------
	// ● Text
	//-------------------------------------------------------------------------
	class TextRenderer : public RenderObject {
	private:
		GDrawable obj;
		Res::Texture tex = Res::Texture("../Media/Font.bmp", &Res::LinearTextureParameters);
		Shaders texshader;

	public:
		enum TextDecorationType {
			NONE,
			SHADOW,
			OUTLINE,
		};
		TextRenderer();
		void BakeText(
			const char* text,
			float width, float height,
			TextDecorationType decoration
		);
		void render();
		void instanceRenderText(
			const char* text,
			glm::mat4 projection, glm::mat4 view, glm::mat4 transform,
			float width, float height, TextDecorationType decoration
		);
	};

	//-------------------------------------------------------------------------
	// ● RenderBuffer
	//-------------------------------------------------------------------------
	class RenderBuffer : public Object {
	public:
		GLuint framebuffer;
		GLuint rbo;
		Res::Texture** texture_buffer;
		int mrtcount;

		//void resize(int w, int h);

		void bind();
		static void unbind();
		static void clearColor(float r, float g, float b, float a);
		static void clearColorDepth(float r, float g, float b, float a);
		static void clearDepth();

		RenderBuffer(int w, int h, int mrt, const GLuint* type);
		void set_draw_buffers();
		~RenderBuffer();
	};

	class PostProcessingManager : public Object {
	private:
		static GDrawable* QuadScreen;

	public:
		static void init();
		static void Blit2D();
	};

#endif
<|endoftext|>


<commit_before>//
//  GEORenderer.hpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 11/30/12.
//
//

#ifndef __G3MiOSSDK__GEORenderer__
#define __G3MiOSSDK__GEORenderer__

#include "LeafRenderer.hpp"

#include <vector>
class GEOObject;

class GEORenderer : public LeafRenderer {
private:
  const G3MContext*       _context;
  std::vector<GEOObject*> _children;

public:

  void addGEOObject(GEOObject* geoObject);

  void onResume(const G3MContext* context) {

  }

  void onPause(const G3MContext* context) {

  }

  void onDestroy(const G3MContext* context) {

  }

  void initialize(const G3MContext* context);

  bool isReadyToRender(const G3MRenderContext* rc);

  void render(const G3MRenderContext* rc);

  bool onTouchEvent(const G3MEventContext* ec,
                    const TouchEvent* touchEvent) {
    return false;
  }

  void onResizeViewportEvent(const G3MEventContext* ec,
                             int width, int height) {

  }

  void start() {

  }

  void stop() {

  }

};

#endif
<commit_msg>First version of GEORenderer - not yet usable<commit_after>//
//  GEORenderer.hpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 11/30/12.
//
//

#ifndef __G3MiOSSDK__GEORenderer__
#define __G3MiOSSDK__GEORenderer__

#include "LeafRenderer.hpp"

#include <vector>
class GEOObject;

class GEORenderer : public LeafRenderer {
private:
#ifdef C_CODE
  const G3MContext* _context;
#endif
#ifdef JAVA_CODE
  private G3MContext _context;
#endif
  std::vector<GEOObject*> _children;

public:

  void addGEOObject(GEOObject* geoObject);

  void onResume(const G3MContext* context) {

  }

  void onPause(const G3MContext* context) {

  }

  void onDestroy(const G3MContext* context) {

  }

  void initialize(const G3MContext* context);

  bool isReadyToRender(const G3MRenderContext* rc);

  void render(const G3MRenderContext* rc);

  bool onTouchEvent(const G3MEventContext* ec,
                    const TouchEvent* touchEvent) {
    return false;
  }

  void onResizeViewportEvent(const G3MEventContext* ec,
                             int width, int height) {

  }

  void start() {

  }

  void stop() {

  }

};

#endif
<|endoftext|>


<commit_before>/**
 * \file dcs/testbed/system_identification.hpp
 *
 * \brief Performs system identification experiments.
 *
 * \author Marco Guazzone (marco.guazzone@gmail.com)
 *
 *

 *
 * Copyright (C) 2012       Marco Guazzone
 *                          [Distributed Computing System (DCS) Group,
 *                           Computer Science Institute,
 *                           Department of Science and Technological Innovation,
 *                           University of Piemonte Orientale,
 *                           Alessandria (Italy)]
 *
 * This file is part of dcsxx-testbed.
 *
 * dcsxx-testbed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * dcsxx-testbed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with dcsxx-testbed.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef DCS_TESTBED_SYSTEM_IDENTIFICATION_HPP
#define DCS_TESTBED_SYSTEM_IDENTIFICATION_HPP

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/smart_ptr.hpp>
#include <cstddef>
#include <ctime>
#include <dcs/assert.hpp>
#include <dcs/debug.hpp>
#include <dcs/exception.hpp>
#include <dcs/testbed/base_signal_generator.hpp>
#include <dcs/testbed/base_virtual_machine.hpp>
#include <dcs/testbed/base_workload_driver.hpp>
#include <fstream>
#include <iterator>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unistd.h>
#include <vector>

#ifdef DCS_DEBUG
# include <boost/numeric/ublas/io.hpp>
#endif // DCS_DEBUG

namespace dcs { namespace testbed {

template <typename RealT>
class system_identification
{
	public: typedef RealT real_type;
	public: typedef base_virtual_machine<real_type> vm_type;
	public: typedef ::boost::shared_ptr<vm_type> vm_pointer;
	public: typedef base_signal_generator<real_type> signal_generator_type;
	public: typedef ::boost::shared_ptr<signal_generator_type> signal_generator_pointer;
	public: typedef base_workload_driver workload_driver_type;
	public: typedef ::boost::shared_ptr<workload_driver_type> workload_driver_pointer;
	private: typedef ::std::vector<vm_pointer> vm_container;

	private: static const unsigned int default_sampling_time = 10;
	private: static const ::std::string default_output_data_file_path;

	/// Default constructor.
	public: system_identification()
	: ts_(default_sampling_time),
	  out_dat_file_(default_output_data_file_path),
	  out_ext_fmt_(false)
	{
	}

	/// A constructor.
	public: template <typename FwdIterT>
			system_identification(FwdIterT vm_first, FwdIterT vm_last, workload_driver_pointer const& p_wkl_driver, signal_generator_pointer const& p_sig_gen)
	: vms_(vm_first, vm_last),
	  p_wkl_driver_(p_wkl_driver),
	  p_sig_gen_(p_sig_gen),
	  ts_(default_sampling_time),
	  out_dat_file_(default_output_data_file_path),
	  out_ext_fmt_(false)
	{
	}

	/// Set the path of the output data file.
	public: void output_data_file(::std::string const& s)
	{
		// pre: s != ""
		DCS_ASSERT(!s.empty(),
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Cannot use empty string as output data file name"));

		out_dat_file_ = s;
	}

	/// Enabled or disable the extended format of the output data file.
	public: void output_extended_format(bool val)
	{
		out_ext_fmt_ = val;
	}

	/// Set the sampling time.
	public: void sampling_time(real_type t)
	{
		// pre: t > 0
		DCS_ASSERT(t > 0,
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Sampling time must be positive"));
		// pre: t <= max value
		DCS_ASSERT(t <= ::std::numeric_limits<unsigned int>::max(),
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Sampling time too large"));

		ts_ = static_cast<unsigned int>(t);
	}

	/**
	 * \brief Perform system identification by using as initial shares the
	 *  100% of resource.
	 */
	public: void run()
	{
		::std::vector<real_type> init_shares(vms_.size(), 1);

		this->run(init_shares.begin(), init_shares.end());
	}

	/**
	 * \brief Perform system identification with the given initial shares.
	 */
	public: template <typename FwdIterT>
			void run(FwdIterT share_first, FwdIterT share_end)
	{
		// distance(share_first,share_end) == size(vms_)
		DCS_ASSERT(static_cast< ::std::size_t >(::std::distance(share_first, share_end)) == vms_.size(),
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Share container size does not match"));

		typedef typename vm_container::const_iterator vm_iterator;
		typedef typename signal_generator_type::vector_type share_container;

		//const ::std::size_t nt(10);//FIXME: parameterize

		// Open output data file
		::std::ofstream ofs(out_dat_file_.c_str());
		if (!ofs.good())
		{
			::std::ostringstream oss;
			oss << "Cannot open output data file '" << out_dat_file_ << "'";

			DCS_EXCEPTION_THROW(::std::runtime_error, oss.str());
		}

		// Set initial shares
		vm_iterator vm_end_it(vms_.end());
		vm_iterator vm_beg_it(vms_.begin());
		for (vm_iterator vm_it = vm_beg_it;
			 vm_it != vm_end_it;
			 ++vm_it)
		{
			vm_pointer p_vm(*vm_it);

			p_vm->cpu_share(*share_first);
			++share_first;
		}

		// Start the workload driver
		p_wkl_driver_->start();

		// Set shares according to the given signal
		::std::time_t t0;
		::std::time_t t1;
		t0 = ::std::time(&t1);
		while (!p_wkl_driver_->done())
		{
			if (p_wkl_driver_->ready() && p_wkl_driver_->has_observation())
			{
				// Stringstream used to hold common output info
				::std::ostringstream oss;

				// Compute the elapsed time
				t0 = t1;
				::std::time(&t1);
				double dt = ::std::difftime(t1, t0);

				DCS_DEBUG_TRACE( "-- Time " << dt );

				oss << dt;

				// Generate new shares
				share_container share((*p_sig_gen_)());

				// check: consistency
				DCS_DEBUG_ASSERT( share.size() == vms_.size() );

				DCS_DEBUG_TRACE( "   Generated shares: " << dcs::debug::to_string(share.begin(), share.end()) );

				// Set new shares to every VM
				::std::size_t ix(0);
				for (vm_iterator vm_it = vm_beg_it;
					 vm_it != vm_end_it;
					 ++vm_it)
				{
					vm_pointer p_vm(*vm_it);

					// check: not null
					DCS_DEBUG_ASSERT( p_vm );

					DCS_DEBUG_TRACE( "   VM '" << p_vm->name() << "' :: Old CPU share: " << p_vm->cpu_share() << " :: New CPU share: " << share[ix] );

					oss << " " << p_vm->cpu_share();

					p_vm->cpu_share(share[ix]);

					++ix;
				}

				// Get collected observations
				typedef ::std::vector<real_type> obs_container;
				typedef typename obs_container::const_iterator obs_iterator;
				obs_container obs = p_wkl_driver_->observations();
				//FIXME: parameterize the type of statistics the user want
				::boost::accumulators::accumulator_set< real_type, ::boost::accumulators::stats< ::boost::accumulators::tag::mean > > acc;
				obs_iterator obs_end_it(obs.end());
				for (obs_iterator obs_it = obs.begin();
					 obs_it != obs_end_it;
					 ++obs_it)
				{
					real_type val(*obs_it);
					acc(val);

					if (out_ext_fmt_)
					{
						ofs << oss.str() << " " << val << " " << "\"[DATA]\"" << ::std::endl;
					}
				}

				// Compute a summary statistics of collected observation
				//FIXME: parameterize the type of statistics the user want
				real_type summary_obs = ::boost::accumulators::mean(acc);

				DCS_DEBUG_TRACE( "   Current (summary) observation: " << summary_obs );

				if (out_ext_fmt_)
				{
					ofs << oss.str() << " " << summary_obs << " " << "\"[SUMMARY]\"" << ::std::endl;
				}
				else
				{
					ofs << oss.str() << " " << summary_obs << ::std::endl;
				}

				// Wait until the next sampling time
				::sleep(ts_);
			}
		}

		// Stop the workload driver
		p_wkl_driver_->stop();

		// Close output data file
		ofs.close();
	}

	private: vm_container vms_; ///< VMs container
	private: workload_driver_pointer p_wkl_driver_; ///< Ptr to workload driver
	private: signal_generator_pointer p_sig_gen_; ///< Ptr to signal generator used to excite VMs
	private: unsigned int ts_; ///< The sampling time
	private: ::std::string out_dat_file_; ///< The path to the output data file
	private: bool out_ext_fmt_; ///< Flag to control whether to produce an output data file with extended format
}; // system_identification

template <typename RealT>
const ::std::string system_identification<RealT>::default_output_data_file_path("./sysid_out.dat");

}} // Namespace dcs::testbed

#endif // DCS_TESTBED_SYSTEM_IDENTIFICATION_HPP
<commit_msg>(bug-fix:minor) Restore old shares before leaving the system identification 'run' method.<commit_after>/**
 * \file dcs/testbed/system_identification.hpp
 *
 * \brief Performs system identification experiments.
 *
 * \author Marco Guazzone (marco.guazzone@gmail.com)
 *
 *

 *
 * Copyright (C) 2012       Marco Guazzone
 *                          [Distributed Computing System (DCS) Group,
 *                           Computer Science Institute,
 *                           Department of Science and Technological Innovation,
 *                           University of Piemonte Orientale,
 *                           Alessandria (Italy)]
 *
 * This file is part of dcsxx-testbed.
 *
 * dcsxx-testbed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * dcsxx-testbed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with dcsxx-testbed.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef DCS_TESTBED_SYSTEM_IDENTIFICATION_HPP
#define DCS_TESTBED_SYSTEM_IDENTIFICATION_HPP

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/smart_ptr.hpp>
#include <cstddef>
#include <ctime>
#include <dcs/assert.hpp>
#include <dcs/debug.hpp>
#include <dcs/exception.hpp>
#include <dcs/testbed/base_signal_generator.hpp>
#include <dcs/testbed/base_virtual_machine.hpp>
#include <dcs/testbed/base_workload_driver.hpp>
#include <fstream>
#include <iterator>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unistd.h>
#include <vector>

#ifdef DCS_DEBUG
# include <boost/numeric/ublas/io.hpp>
#endif // DCS_DEBUG

namespace dcs { namespace testbed {

template <typename RealT>
class system_identification
{
	public: typedef RealT real_type;
	public: typedef base_virtual_machine<real_type> vm_type;
	public: typedef ::boost::shared_ptr<vm_type> vm_pointer;
	public: typedef base_signal_generator<real_type> signal_generator_type;
	public: typedef ::boost::shared_ptr<signal_generator_type> signal_generator_pointer;
	public: typedef base_workload_driver workload_driver_type;
	public: typedef ::boost::shared_ptr<workload_driver_type> workload_driver_pointer;
	private: typedef ::std::vector<vm_pointer> vm_container;

	private: static const unsigned int default_sampling_time = 10;
	private: static const ::std::string default_output_data_file_path;

	/// Default constructor.
	public: system_identification()
	: ts_(default_sampling_time),
	  out_dat_file_(default_output_data_file_path),
	  out_ext_fmt_(false)
	{
	}

	/// A constructor.
	public: template <typename FwdIterT>
			system_identification(FwdIterT vm_first, FwdIterT vm_last, workload_driver_pointer const& p_wkl_driver, signal_generator_pointer const& p_sig_gen)
	: vms_(vm_first, vm_last),
	  p_wkl_driver_(p_wkl_driver),
	  p_sig_gen_(p_sig_gen),
	  ts_(default_sampling_time),
	  out_dat_file_(default_output_data_file_path),
	  out_ext_fmt_(false)
	{
	}

	/// Set the path of the output data file.
	public: void output_data_file(::std::string const& s)
	{
		// pre: s != ""
		DCS_ASSERT(!s.empty(),
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Cannot use empty string as output data file name"));

		out_dat_file_ = s;
	}

	/// Enabled or disable the extended format of the output data file.
	public: void output_extended_format(bool val)
	{
		out_ext_fmt_ = val;
	}

	/// Set the sampling time.
	public: void sampling_time(real_type t)
	{
		// pre: t > 0
		DCS_ASSERT(t > 0,
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Sampling time must be positive"));
		// pre: t <= max value
		DCS_ASSERT(t <= ::std::numeric_limits<unsigned int>::max(),
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Sampling time too large"));

		ts_ = static_cast<unsigned int>(t);
	}

	/**
	 * \brief Perform system identification by using as initial shares the
	 *  100% of resource.
	 */
	public: void run()
	{
		::std::vector<real_type> init_shares(vms_.size(), 1);

		this->run(init_shares.begin(), init_shares.end());
	}

	/**
	 * \brief Perform system identification with the given initial shares.
	 */
	public: template <typename FwdIterT>
			void run(FwdIterT share_first, FwdIterT share_end)
	{
		// distance(share_first,share_end) == size(vms_)
		DCS_ASSERT(static_cast< ::std::size_t >(::std::distance(share_first, share_end)) == vms_.size(),
				   DCS_EXCEPTION_THROW(::std::invalid_argument,
									   "Share container size does not match"));

		typedef typename vm_container::const_iterator vm_iterator;
		typedef typename signal_generator_type::vector_type share_container;
		typedef typename vm_type::identifier_type vm_identifier_type;

		DCS_DEBUG_TRACE( "BEGIN Execution of System Identification" );

		vm_iterator vm_end_it(vms_.end());
		vm_iterator vm_beg_it(vms_.begin());

		if (vm_beg_it == vm_end_it)
		{
			// No VMs -> don't run anything
			return;
		}

		// Open output data file
		::std::ofstream ofs(out_dat_file_.c_str());
		if (!ofs.good())
		{
			::std::ostringstream oss;
			oss << "Cannot open output data file '" << out_dat_file_ << "'";

			DCS_EXCEPTION_THROW(::std::runtime_error, oss.str());
		}

		// Get current shares in order to restore them at the end of execution
		share_container old_shares;
		for (vm_iterator vm_it = vm_beg_it;
			 vm_it != vm_end_it;
			 ++vm_it)
		{
			vm_pointer p_vm(*vm_it);

			old_shares.push_back(p_vm->cpu_share());
		}

		// Set initial shares
		for (vm_iterator vm_it = vm_beg_it;
			 vm_it != vm_end_it;
			 ++vm_it)
		{
			vm_pointer p_vm(*vm_it);

			p_vm->cpu_share(*share_first);
			++share_first;
		}

		// Start the workload driver
		p_wkl_driver_->start();

		// Set shares according to the given signal
		::std::time_t t0(-1);
		::std::time_t t1(-1);
		::std::time(&t1);
		while (!p_wkl_driver_->done())
		{
			DCS_DEBUG_TRACE( "   Driver is alive" );
			if (p_wkl_driver_->ready() && p_wkl_driver_->has_observation())
			{
				// Stringstream used to hold common output info
				::std::ostringstream oss;

				// Compute the elapsed time
				::std::time(&t1);
				if (t0 == -1)
				{
					// Set t0 to the start of observation collection phase
					t0 = t1;
				}
				double dt = ::std::difftime(t1, t0);

				DCS_DEBUG_TRACE( "-- Time " << dt );

				oss << dt;

				// Generate new shares
				share_container share((*p_sig_gen_)());

				// check: consistency
				DCS_DEBUG_ASSERT( share.size() == vms_.size() );

				DCS_DEBUG_TRACE( "   Generated shares: " << dcs::debug::to_string(share.begin(), share.end()) );

				// Set new shares to every VM
				::std::size_t ix(0);
				for (vm_iterator vm_it = vm_beg_it;
					 vm_it != vm_end_it;
					 ++vm_it)
				{
					vm_pointer p_vm(*vm_it);

					// check: not null
					DCS_DEBUG_ASSERT( p_vm );

					DCS_DEBUG_TRACE( "   VM '" << p_vm->name() << "' :: Old CPU share: " << p_vm->cpu_share() << " :: New CPU share: " << share[ix] );

					oss << " " << p_vm->cpu_share();

					p_vm->cpu_share(share[ix]);

					++ix;
				}

				// Get collected observations
				typedef ::std::vector<real_type> obs_container;
				typedef typename obs_container::const_iterator obs_iterator;
				obs_container obs = p_wkl_driver_->observations();
				//FIXME: parameterize the type of statistics the user want
				::boost::accumulators::accumulator_set< real_type, ::boost::accumulators::stats< ::boost::accumulators::tag::mean > > acc;
				obs_iterator obs_end_it(obs.end());
				for (obs_iterator obs_it = obs.begin();
					 obs_it != obs_end_it;
					 ++obs_it)
				{
					real_type val(*obs_it);
					acc(val);

					if (out_ext_fmt_)
					{
						ofs << oss.str() << " " << val << " " << "\"[DATA]\"" << ::std::endl;
					}
				}

				// Compute a summary statistics of collected observation
				//FIXME: parameterize the type of statistics the user want
				real_type summary_obs = ::boost::accumulators::mean(acc);

				DCS_DEBUG_TRACE( "   Current (summary) observation: " << summary_obs );

				if (out_ext_fmt_)
				{
					ofs << oss.str() << " " << summary_obs << " " << "\"[SUMMARY]\"" << ::std::endl;
				}
				else
				{
					ofs << oss.str() << " " << summary_obs << ::std::endl;
				}

				// Wait until the next sampling time
				DCS_DEBUG_TRACE( "   Zzz... (: " << ts_ << ")" );
				::sleep(ts_);
			}
		}

		// Stop the workload driver
		p_wkl_driver_->stop();

		// Close output data file
		ofs.close();

		// Reset VM shares to values that VMs had just before running the driver
		::std::size_t ix(0);
		for (vm_iterator vm_it = vm_beg_it;
			 vm_it != vm_end_it;
			 ++vm_it)
		{
			vm_pointer p_vm(*vm_it);

			p_vm->cpu_share(old_shares[ix]);
			++ix;
		}

		DCS_DEBUG_TRACE( "END Execution of System Identification" );
	}

	private: vm_container vms_; ///< VMs container
	private: workload_driver_pointer p_wkl_driver_; ///< Ptr to workload driver
	private: signal_generator_pointer p_sig_gen_; ///< Ptr to signal generator used to excite VMs
	private: unsigned int ts_; ///< The sampling time
	private: ::std::string out_dat_file_; ///< The path to the output data file
	private: bool out_ext_fmt_; ///< Flag to control whether to produce an output data file with extended format
}; // system_identification

template <typename RealT>
const ::std::string system_identification<RealT>::default_output_data_file_path("./sysid_out.dat");

}} // Namespace dcs::testbed

#endif // DCS_TESTBED_SYSTEM_IDENTIFICATION_HPP
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * GHOUL                                                                                *
 * General Helpful Open Utility Library                                                  *
 *                                                                                *
 * Copyright (c) 2012-2014                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

namespace ghoul {
namespace cmdparser {

template<typename T, typename U = T, typename V = U, typename W = V>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, const std::string& name,
                             const std::string& shortName,
                             const std::string& infoText,
                             const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 1, false)
	, _ptr1(ptr1)
	, _ptr2(nullptr)
	, _ptr3(nullptr)
	, _ptr4(nullptr)
{}

template<typename T, typename U = T, typename V = U, typename W = V>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, U* ptr2, const std::string& name,
                             const std::string&  shortName,
                             const std::string& infoText,
                             const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 2, false)
	, _ptr1(ptr1)
	, _ptr2(ptr2)
	, _ptr3(nullptr)
	, _ptr4(nullptr)
{}

template<typename T, typename U = T, typename V = U, typename W = V>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, U* ptr2, V* ptr3,
							const std::string& name,
                             const std::string& shortName,
                             const std::string& infoText,
                             const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 3, false)
	, _ptr1(ptr1)
	, _ptr2(ptr2)
	, _ptr3(ptr3)
	, _ptr4(nullptr)
{}

template<typename T, typename U = T, typename V = U, typename W = V>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, U* ptr2, V* ptr3, W* ptr4,
							 const std::string& name,
							 const std::string& shortName,
							 const std::string& infoText,
							 const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 4, false)
	, _ptr1(ptr1)
	, _ptr2(ptr2)
	, _ptr3(ptr3)
	, _ptr4(ptr4)
{}

template<typename T, typename U = T, typename V = U, typename W = V>
bool SingleCommand<T, U, V, W>::execute(const std::vector<std::string>& parameters) {
    cast(parameters[0], *_ptr1);
    if (_ptr2 != nullptr)
        cast(parameters[1], *_ptr2);
    if (_ptr3 != nullptr)
        cast(parameters[2], *_ptr3);
    if (_ptr4 != nullptr)
        cast(parameters[3], *_ptr4);

    return true;
}

template<typename T, typename U = T, typename V = U, typename W = V>
bool SingleCommand<T, U, V, W>::checkParameters(
										const std::vector<std::string>& parameters)
{
    std::ostringstream errorStr;

    bool result = parameters.size() == static_cast<size_t>(_argumentNum);
    if (!result) {
        errorStr << "Invalid number of parameters: " << parameters.size();
        errorStr << ", expected: " << _argumentNum;
        _errorMsg = errorStr.str();
        return false;
    }

    result &= is<T>(parameters[0]);
    if (!result)
        errorStr << "First parameter invalid";

    if (result && (_ptr2 != nullptr)) {
        result &= is<U>(parameters[1]);
        if (!result)
            errorStr << "Second parameter invalid";
    }

    if (result && (_ptr3 != nullptr)) {
        result &= is<V>(parameters[2]);
        if (!result)
            errorStr << "Third parameter invalid";
    }

    if (result && (_ptr4 != nullptr)) {
        result &= is<W>(parameters[3]);
        if (!result)
            errorStr << "Fourth parameter invalid";
    }

    if (!result)
        _errorMsg = errorStr.str();

    return result;
}

} // namespace cmdparser
} // namespace ghoul<commit_msg>Linux fix<commit_after>/*****************************************************************************************
 *                                                                                *
 * GHOUL                                                                                *
 * General Helpful Open Utility Library                                                  *
 *                                                                                *
 * Copyright (c) 2012-2014                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

namespace ghoul {
namespace cmdparser {

template<typename T, typename U, typename V, typename W>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, const std::string& name,
                             const std::string& shortName,
                             const std::string& infoText,
                             const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 1, false)
	, _ptr1(ptr1)
	, _ptr2(nullptr)
	, _ptr3(nullptr)
	, _ptr4(nullptr)
{}

template<typename T, typename U, typename V, typename W>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, U* ptr2, const std::string& name,
                             const std::string&  shortName,
                             const std::string& infoText,
                             const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 2, false)
	, _ptr1(ptr1)
	, _ptr2(ptr2)
	, _ptr3(nullptr)
	, _ptr4(nullptr)
{}

template<typename T, typename U, typename V, typename W>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, U* ptr2, V* ptr3,
							const std::string& name,
                             const std::string& shortName,
                             const std::string& infoText,
                             const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 3, false)
	, _ptr1(ptr1)
	, _ptr2(ptr2)
	, _ptr3(ptr3)
	, _ptr4(nullptr)
{}

template<typename T, typename U, typename V, typename W>
SingleCommand<T, U, V, W>::SingleCommand(T* ptr1, U* ptr2, V* ptr3, W* ptr4,
							 const std::string& name,
							 const std::string& shortName,
							 const std::string& infoText,
							 const std::string parameterList)
    : CommandlineCommand(name, shortName, infoText, parameterList, 4, false)
	, _ptr1(ptr1)
	, _ptr2(ptr2)
	, _ptr3(ptr3)
	, _ptr4(ptr4)
{}

template<typename T, typename U, typename V, typename W>
bool SingleCommand<T, U, V, W>::execute(const std::vector<std::string>& parameters) {
    cast(parameters[0], *_ptr1);
    if (_ptr2 != nullptr)
        cast(parameters[1], *_ptr2);
    if (_ptr3 != nullptr)
        cast(parameters[2], *_ptr3);
    if (_ptr4 != nullptr)
        cast(parameters[3], *_ptr4);

    return true;
}

template<typename T, typename U, typename V, typename W>
bool SingleCommand<T, U, V, W>::checkParameters(
										const std::vector<std::string>& parameters)
{
    std::ostringstream errorStr;

    bool result = parameters.size() == static_cast<size_t>(_argumentNum);
    if (!result) {
        errorStr << "Invalid number of parameters: " << parameters.size();
        errorStr << ", expected: " << _argumentNum;
        _errorMsg = errorStr.str();
        return false;
    }

    result &= is<T>(parameters[0]);
    if (!result)
        errorStr << "First parameter invalid";

    if (result && (_ptr2 != nullptr)) {
        result &= is<U>(parameters[1]);
        if (!result)
            errorStr << "Second parameter invalid";
    }

    if (result && (_ptr3 != nullptr)) {
        result &= is<V>(parameters[2]);
        if (!result)
            errorStr << "Third parameter invalid";
    }

    if (result && (_ptr4 != nullptr)) {
        result &= is<W>(parameters[3]);
        if (!result)
            errorStr << "Fourth parameter invalid";
    }

    if (!result)
        _errorMsg = errorStr.str();

    return result;
}

} // namespace cmdparser
} // namespace ghoul<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_POSITIONS_GRAMMAR_HPP
#define MAPNIK_JSON_POSITIONS_GRAMMAR_HPP

// mapnik
#include <mapnik/util/variant.hpp>
#include <mapnik/json/generic_json.hpp>
#include <mapnik/json/error_handler.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_fusion_adapted.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#pragma GCC diagnostic pop

// stl
#include <tuple>

namespace mapnik { namespace json {

struct empty {};

using position = mapnik::geometry::point<double>;
using positions = std::vector<position>;
using coordinates = util::variant<empty, position, positions, std::vector<positions>, std::vector<std::vector<positions> > > ;

namespace qi = boost::spirit::qi;

struct set_position_impl
{
    using result_type = void;
    template <typename T0,typename T1>
    result_type operator() (T0 & coords, T1 const& pos) const
    {
        if (pos) coords = *pos;
    }
};

struct push_position_impl
{
    using result_type = void;
    template <typename T0,typename T1>
    result_type operator() (T0 & coords, T1 const& pos) const
    {
        if (pos) coords.push_back(*pos);
    }
};

template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
struct positions_grammar :
        qi::grammar<Iterator,coordinates(),space_type>
{
    positions_grammar(ErrorHandler & error_handler);
    qi::rule<Iterator, coordinates(),space_type> coords;
    qi::rule<Iterator, boost::optional<position>(), space_type> pos;
    qi::rule<Iterator, positions(), space_type> ring;
    qi::rule<Iterator, std::vector<positions>(), space_type> rings;
    qi::rule<Iterator, std::vector<std::vector<positions> >(), space_type> rings_array;
    boost::phoenix::function<set_position_impl> set_position;
    boost::phoenix::function<push_position_impl> push_position;
};

}}

#endif // MAPNIK_JSON_POSITIONS_GRAMMAR_HPP
<commit_msg>keep address-sanitizer happy ref (https://github.com/mapbox/mapnik-vector-tile/pull/171)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_POSITIONS_GRAMMAR_HPP
#define MAPNIK_JSON_POSITIONS_GRAMMAR_HPP

// mapnik
#include <mapnik/util/variant.hpp>
#include <mapnik/json/generic_json.hpp>
#include <mapnik/json/error_handler.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_fusion_adapted.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#pragma GCC diagnostic pop

// stl
#include <tuple>

namespace mapnik { namespace json {

struct empty {};

using position = mapnik::geometry::point<double>;
using positions = std::vector<position>;
using coordinates = util::variant<empty, position, positions, std::vector<positions>, std::vector<std::vector<positions> > > ;

namespace qi = boost::spirit::qi;

struct set_position_impl
{
    using result_type = void;
    template <typename T0,typename T1>
    result_type operator() (T0 & coords, T1 const& pos) const
    {
        if (pos) coords = *pos;
    }
};

struct push_position_impl
{
    using result_type = void;
    template <typename T0, typename T1>
    result_type operator() (T0 & coords, T1 const& pos) const
    {
        if (pos) coords.empace_back(*pos);
    }
};

template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
struct positions_grammar :
        qi::grammar<Iterator,coordinates(),space_type>
{
    positions_grammar(ErrorHandler & error_handler);
    qi::rule<Iterator, coordinates(),space_type> coords;
    qi::rule<Iterator, boost::optional<position>(), space_type> pos;
    qi::rule<Iterator, positions(), space_type> ring;
    qi::rule<Iterator, std::vector<positions>(), space_type> rings;
    qi::rule<Iterator, std::vector<std::vector<positions> >(), space_type> rings_array;
    boost::phoenix::function<set_position_impl> set_position;
    boost::phoenix::function<push_position_impl> push_position;
};

}}

#endif // MAPNIK_JSON_POSITIONS_GRAMMAR_HPP
<|endoftext|>