<commit_before>/******************************************************************
 * Author: Mgumbo
 *
 * Date Completed: 13 April 2016
 *
 * Description: A file containing all of the implementation for the
 *				LinkedList class.
 *******************************************************************/
#include "LinkedList.h"
#include <assert.h>

namespace DataStructures
{
	/**
	 * Default constructor. Creates a sentinel Node that,
	 * until more items are added, just links to itself.
	 **/
	template <class T>
	LinkedList<T>::LinkedList()
	{
		//create a sentinel Node that points to itself and has no value
		_sentinelNode = new Node<T>();
		_sentinelNode->setNextNode(_sentinelNode);
		_sentinelNode->setPrevNode(_sentinelNode);
	} //end constructor

	/**
	 * Copy constructor. Resets the sentinel Node, and then copies each
	 * element from the passed LinkedList to this one.
	 **/
	template <class T>
	LinkedList<T>::LinkedList(const LinkedList& original)
	{
		//reset this LinkedList's sentinel Node
		_sentinelNode = new Node<T>();
		_sentinelNode->setNextNode(_sentinelNode);
		_sentinelNode->setPrevNode(_sentinelNode);

		//move through each item in the original list
		for (Node<T>* move = original._sentinelNode->getNextNode();
			move != original._sentinelNode; move = move->getNextNode())
		{
			//create new Node at end of LinkedList
			Node<T>* temp = new Node<T>(move->getItem(),
				_sentinelNode,
				_sentinelNode->getPrevNode());

			//attach new Node
			temp->getPrevNode()->setNextNode(temp);
			temp->getNextNode()->setPrevNode(temp);
		} //end for
	} //end constructor

	/**
	 * Destructor; this is called when the object is destroyed.
	 * Loops through the entire LinkedList and deletes all of
	 * the pointers, freeing up memory.
	 **/
	template <class T>
	LinkedList<T>::~LinkedList()
	{
		clear(); //delete everything but sentinel

		//delete sentinel
		delete _sentinelNode;
	} //end destructor

	/**
	 * Returns the front element in the LinkedList.
	 **/
	template <class T>
	T LinkedList<T>::getFront() const
	{
		//Node AFTER sentinel Node is the front
		return _sentinelNode->getNextNode()->getItem();
	} //end getFront

	/**
	 * Returns the back element in the LinkedList.
	 **/
	template <class T>
	T LinkedList<T>::getBack() const
	{
		//Node BEFORE sentinel Node is the back
		return _sentinelNode->getPrevNode()->getItem();
	} //end getBack

	/**
	 * Returns an Iterator that points to the Node AFTER
	 * the sentinel Node. Since the sentinel Node is connected
	 * to the front and back of the LinkedList, the Node
	 * after the sentinel Node holds the front item in the
	 * LinkedList.
	 **/
	template <class T>
	Iterator<T> LinkedList<T>::begin() const
	{
		return Iterator<T>(this, _sentinelNode->getNextNode());
	} //end begin

	/**
	 * Returns an Iterator that points to the sentinel Node of
	 * the LinkedList. The Node that is pointed to does not
	 * have a value and serves only as a mark for the end of
	 * the LinkedList.
	 **/
	template <class T>
	Iterator<T> LinkedList<T>::end() const
	{
		return Iterator<T>(this, _sentinelNode);
	} //end end

	/**
	 * Pushes a specified item to the front of the LinkedList.
	 * Takes a generic-type parameter, and then creates an
	 * associating Node, which is then added to the front of
	 * the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::pushFront(T item)
	{
		assert(!isFull()); //make sure the LinkedList isn't full

		//create new Node that points forward to sentinel's next node
		//and backward to sentinel
		Node<T>* temp = new Node<T>(item, _sentinelNode->getNextNode(), _sentinelNode);

		//link the new Node to the next Node...
		temp->getNextNode()->setPrevNode(temp);

		//...then link the new Node to the previous Node
		temp->getPrevNode()->setNextNode(temp);
	} //end pushFront

	/**
	 * Pushes a specified item to the back of the LinkedList.
	 * Takes a generic-type parameter, and then creates an
	 * associating Node, which is then added to the back of
	 * the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::pushBack(T item)
	{
		assert(!isFull()); //make sure the LinkedList isn't full

		//create new Node that points forward to sentinel and
		//backward to sentinel's previous Node
		Node<T>* temp = new Node<T>(item, _sentinelNode, _sentinelNode->getPrevNode());

		//link new Node to the next Node...
		temp->getNextNode()->setPrevNode(temp);

		//...then link new Node to the previous Node
		temp->getPrevNode()->setNextNode(temp);
	} //end pushBack

	/**
	 * Removes the front element from the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::popFront()
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temporary Node representing front Node in LinkedList
		Node<T>* temp = _sentinelNode->getNextNode();

		//link the previous Node to the next Node...
		temp->getPrevNode()->setNextNode(temp->getNextNode());

		//...then link the next Node to the previous Node
		temp->getNextNode()->setPrevNode(temp->getPrevNode());

		//delete the now unlinked Node to free memory
		delete temp;
	} //end popFront

	/**
	 * Removes the back element from the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::popBack()
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temporary Node representing the back Node in LinkedList
		Node<T>* temp = _sentinelNode->getPrevNode();

		//link the previous Node to the next Node...
		temp->getPrevNode()->setNextNode(temp->getNextNode());

		//...then link the next Node to the previous Node
		temp->getNextNode()->setPrevNode(temp->getPrevNode());

		//delete the now unlinked Node to free memory
		delete temp;
	} //end popBack

	/**
	 * Inserts a new element into the LinkedList at a specified
	 * index. If the specified index is too large, the new item
	 * is added to the back of the LinkedList; if the specified
	 * index is too small, the new item is added to the front.
	 **/
	template <class T>
	void LinkedList<T>::insert(T item, int index)
	{
		assert(!isFull()); //make sure the LinkedList isn't full

		//if specified index is...
		if (index > getSize()) //larger than LinkedList size
			pushBack(item); //just add to the back
		else if (index <= 0) //zero or negative index
			pushFront(item); //just add to the front
		else //somewhere in the middle
		{
			//temp Node to loop through elements, starting with first
			Node<T>* temp = _sentinelNode->getNextNode();

			//loop through until one Node before appropriate index
			for (int i = 0; i < (index - 1); i++)
				temp = temp->getNextNode(); //move forward one Node

			//create new Node attached to temp's next Node and temp
			Node<T>* newNode = new Node<T>(item, temp->getNextNode(), temp);

			//link the next Node to the new Node
			temp->getNextNode()->setPrevNode(newNode);

			//link the Node pointed to by temp to the new Node
			temp->setNextNode(newNode);
		} //end else
	} //end insert

	/**
	 * Loops through and removes the first occurrence of a specified
	 * item in the LinkedList. If the specified item is not found,
	 * does nothing.
	 **/
	template <class T>
	void LinkedList<T>::erase(T item)
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temp Node to loop through elements, starting with first
		Node<T>* temp = _sentinelNode->getNextNode();

		//move through elements until temp points to Node with
		//specified value or moves through the entire list
		while (temp->getItem() != item && temp != _sentinelNode)
			temp = temp->getNextNode();

		//if not pointing to sentinel, item was found
		if (temp != _sentinelNode)
		{
			//link previous Node to next Node
			temp->getPrevNode()->setNextNode(temp->getNextNode());

			//link next Node to previous Node
			temp->getNextNode()->setPrevNode(temp->getPrevNode());

			delete temp; //remove the now unlinked element
		} //end if
	} //end erase

	/**
	 * Erases the element of the LinkedList at the specified index.
	 * If the index is larger than the size of the LinkedList, this
	 * function just erases the last item. If the index is smaller
	 * than 0, this function erases the first item.
	 **/
	template <class T>
	void LinkedList<T>::eraseIndex(int index)
	{
		//if the specified index is...
		if (index > getSize()) //larger than this list
			popBack(); //just remove back element
		else if (index < 0) //negative
			popFront(); //just remove front element
		else //somewhere in the middle
		{
			//temp Node to loop through elements, starting with first
			Node<T>* temp = _sentinelNode->getNextNode();

			//loop through until at desired Node
			for (int i = 0; i < index; i++)
				temp = temp->getNextNode();

			//link previous Node to next Node
			temp->getPrevNode()->setNextNode(temp->getNextNode());

			//link next Node to previous Node
			temp->getNextNode()->setPrevNode(temp->getPrevNode());

			delete temp; //remove the now unlinked element
		} //end else
	} //end eraseIndex

	/**
	 * Loops through and removes all occurrences of a specified item
	 * in the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::remove(T item)
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temp Node to loop through elements, starting with first
		Node<T>* temp = _sentinelNode->getNextNode();

		//loop through all of the elements
		while (temp != _sentinelNode)
		{
			//hold position of next Node
			Node<T>* nextNode = temp->getNextNode();

			//if the current pointed-to Node matches the specified item
			if (temp->getItem() == item)
			{
				//link previous Node to next Node
				temp->getPrevNode()->setNextNode(temp->getNextNode());

				//link next Node to previous Node
				temp->getNextNode()->setPrevNode(temp->getPrevNode());

				delete temp; //remove the now unlinked element
			} //end if

			temp = nextNode; //move forward one Node
		} //end while
	} //end remove

	/**
	 * Deletes all elements of the LinkedList except the sentinel
	 * Node, which is set to its default state of pointing to
	 * itself (as there is nothing left in the LinkedList).
	 **/
	template <class T>
	void LinkedList<T>::clear()
	{
		//temp Node to loop through elements, starting with first
		Node<T>* temp = _sentinelNode->getNextNode();

		//loop through all Nodes
		while (temp != _sentinelNode)
		{
			Node<T>* nextNode = temp->getNextNode();
			delete temp; //remove the Node
			temp = nextNode; //move onto the next
		} //end while

		//set sentinel to point to itself again
		_sentinelNode->setNextNode(_sentinelNode);
		_sentinelNode->setPrevNode(_sentinelNode);
	} //end clear

	/**
	 * Iterates through the LinkedList, counting each iteration
	 * until the end is reached, and then returns the number of
	 * iterations.
	 **/
	template <class T>
	int LinkedList<T>::getSize() const
	{
		int count = 0; //count number of elements

		//iterate through all elements and count each incrementation
		for (Iterator<T> it = begin(); it != end(); ++it)
			count++;

		return count;
	} //end getSize

	/**
	 * Returns the maximum possible capacity of a LinkedList.
	 **/
	template <class T>
	const int LinkedList<T>::getMaxSize() const
	{
		return MAX_CAPACITY;
	} //end getMaxSize

	/**
	 * Returns true if the LinkedList contains no elements. If
	 * the sentinel Node is not attached to any other Nodes, then
	 * the LinkedList must be empty.
	 **/
	template <class T>
	bool LinkedList<T>::isEmpty() const
	{
		//if the sentinel points to itself, there are no items
		return (_sentinelNode->getNextNode() == _sentinelNode);
	} //end isEmpty

	/**
	 * Checks to see if the LinkedList's current size is equal
	 * to the maximum possible capacity. If true, then the
	 * LinkedList is full and can no longer hold any items.
	 **/
	template <class T>
	bool LinkedList<T>::isFull() const
	{
		return (getSize() == getMaxSize());
	} //end isFull

	/**
	 * Overloads the assignment operator (=). Clears the LinkedList,
	 * then creates and returns a copy of the specified original,
	 * using the copy constructor.
	 **/
	template <class T>
	LinkedList<T> LinkedList<T>::operator=(const LinkedList<T>& original)
	{
		clear(); //clear list

		LinkedList<T> newList(original); //create copy of passed original

		return newList;
	} //end = assignment operator overload

	/**
	 * Overloads the compound addition operator (+=). Takes the contents
	 * of a specified list and pushes those contents to the back of this
	 * one, then returning this object.
	 **/
	template <class T>
	LinkedList<T>& LinkedList<T>::operator+=(const LinkedList<T>& addend)
	{
		//iterate through other list
		//(auto keyword infers return type and makes declared variable that type)
		for (auto it = addend.begin(); it != addend.end(); ++it)
			pushBack(*it); //push that list's items onto this list

		return *this;
	} //end += compound addition operator overload

	/**
	 * Overloads the compound subtraction operator (-=). Removes any
	 * elements from this list that it shares in common with a specified
	 * other list.
	 **/
	template <class T>
	LinkedList<T>& LinkedList<T>::operator-=(const LinkedList<T>& subtrahend)
	{
		//iterate through other list
		//(auto keyword infers return type and makes declared variable that type)
		for (auto it = subtrahend.begin(); it != subtrahend.end(); ++it)
			remove(*it); //remove the first instance of common element

		return *this;
	} //end -= compound subtraction operator overload
} //end namespace<commit_msg>Uploaded files<commit_after>/******************************************************************
 * Author: Mgumbo
 *
 * Date Completed: 13 April 2016
 *
 * Description: A file containing all of the implementation for the
 *		LinkedList class.
 *******************************************************************/
#include "LinkedList.h"
#include <assert.h>

namespace DataStructures
{
	/**
	 * Default constructor. Creates a sentinel Node that,
	 * until more items are added, just links to itself.
	 **/
	template <class T>
	LinkedList<T>::LinkedList()
	{
		//create a sentinel Node that points to itself and has no value
		_sentinelNode = new Node<T>();
		_sentinelNode->setNextNode(_sentinelNode);
		_sentinelNode->setPrevNode(_sentinelNode);
	} //end constructor

	/**
	 * Copy constructor. Resets the sentinel Node, and then copies each
	 * element from the passed LinkedList to this one.
	 **/
	template <class T>
	LinkedList<T>::LinkedList(const LinkedList& original)
	{
		//reset this LinkedList's sentinel Node
		_sentinelNode = new Node<T>();
		_sentinelNode->setNextNode(_sentinelNode);
		_sentinelNode->setPrevNode(_sentinelNode);

		//move through each item in the original list
		for (Node<T>* move = original._sentinelNode->getNextNode();
			move != original._sentinelNode; move = move->getNextNode())
		{
			//create new Node at end of LinkedList
			Node<T>* temp = new Node<T>(move->getItem(),
				_sentinelNode,
				_sentinelNode->getPrevNode());

			//attach new Node
			temp->getPrevNode()->setNextNode(temp);
			temp->getNextNode()->setPrevNode(temp);
		} //end for
	} //end constructor

	/**
	 * Destructor; this is called when the object is destroyed.
	 * Loops through the entire LinkedList and deletes all of
	 * the pointers, freeing up memory.
	 **/
	template <class T>
	LinkedList<T>::~LinkedList()
	{
		clear(); //delete everything but sentinel

		//delete sentinel
		delete _sentinelNode;
	} //end destructor

	/**
	 * Returns the front element in the LinkedList.
	 **/
	template <class T>
	T LinkedList<T>::getFront() const
	{
		//Node AFTER sentinel Node is the front
		return _sentinelNode->getNextNode()->getItem();
	} //end getFront

	/**
	 * Returns the back element in the LinkedList.
	 **/
	template <class T>
	T LinkedList<T>::getBack() const
	{
		//Node BEFORE sentinel Node is the back
		return _sentinelNode->getPrevNode()->getItem();
	} //end getBack

	/**
	 * Returns an Iterator that points to the Node AFTER
	 * the sentinel Node. Since the sentinel Node is connected
	 * to the front and back of the LinkedList, the Node
	 * after the sentinel Node holds the front item in the
	 * LinkedList.
	 **/
	template <class T>
	Iterator<T> LinkedList<T>::begin() const
	{
		return Iterator<T>(this, _sentinelNode->getNextNode());
	} //end begin

	/**
	 * Returns an Iterator that points to the sentinel Node of
	 * the LinkedList. The Node that is pointed to does not
	 * have a value and serves only as a mark for the end of
	 * the LinkedList.
	 **/
	template <class T>
	Iterator<T> LinkedList<T>::end() const
	{
		return Iterator<T>(this, _sentinelNode);
	} //end end

	/**
	 * Pushes a specified item to the front of the LinkedList.
	 * Takes a generic-type parameter, and then creates an
	 * associating Node, which is then added to the front of
	 * the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::pushFront(T item)
	{
		assert(!isFull()); //make sure the LinkedList isn't full

		//create new Node that points forward to sentinel's next node
		//and backward to sentinel
		Node<T>* temp = new Node<T>(item, _sentinelNode->getNextNode(), _sentinelNode);

		//link the new Node to the next Node...
		temp->getNextNode()->setPrevNode(temp);

		//...then link the new Node to the previous Node
		temp->getPrevNode()->setNextNode(temp);
	} //end pushFront

	/**
	 * Pushes a specified item to the back of the LinkedList.
	 * Takes a generic-type parameter, and then creates an
	 * associating Node, which is then added to the back of
	 * the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::pushBack(T item)
	{
		assert(!isFull()); //make sure the LinkedList isn't full

		//create new Node that points forward to sentinel and
		//backward to sentinel's previous Node
		Node<T>* temp = new Node<T>(item, _sentinelNode, _sentinelNode->getPrevNode());

		//link new Node to the next Node...
		temp->getNextNode()->setPrevNode(temp);

		//...then link new Node to the previous Node
		temp->getPrevNode()->setNextNode(temp);
	} //end pushBack

	/**
	 * Removes the front element from the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::popFront()
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temporary Node representing front Node in LinkedList
		Node<T>* temp = _sentinelNode->getNextNode();

		//link the previous Node to the next Node...
		temp->getPrevNode()->setNextNode(temp->getNextNode());

		//...then link the next Node to the previous Node
		temp->getNextNode()->setPrevNode(temp->getPrevNode());

		//delete the now unlinked Node to free memory
		delete temp;
	} //end popFront

	/**
	 * Removes the back element from the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::popBack()
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temporary Node representing the back Node in LinkedList
		Node<T>* temp = _sentinelNode->getPrevNode();

		//link the previous Node to the next Node...
		temp->getPrevNode()->setNextNode(temp->getNextNode());

		//...then link the next Node to the previous Node
		temp->getNextNode()->setPrevNode(temp->getPrevNode());

		//delete the now unlinked Node to free memory
		delete temp;
	} //end popBack

	/**
	 * Inserts a new element into the LinkedList at a specified
	 * index. If the specified index is too large, the new item
	 * is added to the back of the LinkedList; if the specified
	 * index is too small, the new item is added to the front.
	 **/
	template <class T>
	void LinkedList<T>::insert(T item, int index)
	{
		assert(!isFull()); //make sure the LinkedList isn't full

		//if specified index is...
		if (index > getSize()) //larger than LinkedList size
			pushBack(item); //just add to the back
		else if (index <= 0) //zero or negative index
			pushFront(item); //just add to the front
		else //somewhere in the middle
		{
			//temp Node to loop through elements, starting with first
			Node<T>* temp = _sentinelNode->getNextNode();

			//loop through until one Node before appropriate index
			for (int i = 0; i < (index - 1); i++)
				temp = temp->getNextNode(); //move forward one Node

			//create new Node attached to temp's next Node and temp
			Node<T>* newNode = new Node<T>(item, temp->getNextNode(), temp);

			//link the next Node to the new Node
			temp->getNextNode()->setPrevNode(newNode);

			//link the Node pointed to by temp to the new Node
			temp->setNextNode(newNode);
		} //end else
	} //end insert

	/**
	 * Loops through and removes the first occurrence of a specified
	 * item in the LinkedList. If the specified item is not found,
	 * does nothing.
	 **/
	template <class T>
	void LinkedList<T>::erase(T item)
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temp Node to loop through elements, starting with first
		Node<T>* temp = _sentinelNode->getNextNode();

		//move through elements until temp points to Node with
		//specified value or moves through the entire list
		while (temp->getItem() != item && temp != _sentinelNode)
			temp = temp->getNextNode();

		//if not pointing to sentinel, item was found
		if (temp != _sentinelNode)
		{
			//link previous Node to next Node
			temp->getPrevNode()->setNextNode(temp->getNextNode());

			//link next Node to previous Node
			temp->getNextNode()->setPrevNode(temp->getPrevNode());

			delete temp; //remove the now unlinked element
		} //end if
	} //end erase

	/**
	 * Erases the element of the LinkedList at the specified index.
	 * If the index is larger than the size of the LinkedList, this
	 * function just erases the last item. If the index is smaller
	 * than 0, this function erases the first item.
	 **/
	template <class T>
	void LinkedList<T>::eraseIndex(int index)
	{
		//if the specified index is...
		if (index > getSize()) //larger than this list
			popBack(); //just remove back element
		else if (index < 0) //negative
			popFront(); //just remove front element
		else //somewhere in the middle
		{
			//temp Node to loop through elements, starting with first
			Node<T>* temp = _sentinelNode->getNextNode();

			//loop through until at desired Node
			for (int i = 0; i < index; i++)
				temp = temp->getNextNode();

			//link previous Node to next Node
			temp->getPrevNode()->setNextNode(temp->getNextNode());

			//link next Node to previous Node
			temp->getNextNode()->setPrevNode(temp->getPrevNode());

			delete temp; //remove the now unlinked element
		} //end else
	} //end eraseIndex

	/**
	 * Loops through and removes all occurrences of a specified item
	 * in the LinkedList.
	 **/
	template <class T>
	void LinkedList<T>::remove(T item)
	{
		assert(!isEmpty()); //make sure the LinkedList isn't empty

		//temp Node to loop through elements, starting with first
		Node<T>* temp = _sentinelNode->getNextNode();

		//loop through all of the elements
		while (temp != _sentinelNode)
		{
			//hold position of next Node
			Node<T>* nextNode = temp->getNextNode();

			//if the current pointed-to Node matches the specified item
			if (temp->getItem() == item)
			{
				//link previous Node to next Node
				temp->getPrevNode()->setNextNode(temp->getNextNode());

				//link next Node to previous Node
				temp->getNextNode()->setPrevNode(temp->getPrevNode());

				delete temp; //remove the now unlinked element
			} //end if

			temp = nextNode; //move forward one Node
		} //end while
	} //end remove

	/**
	 * Deletes all elements of the LinkedList except the sentinel
	 * Node, which is set to its default state of pointing to
	 * itself (as there is nothing left in the LinkedList).
	 **/
	template <class T>
	void LinkedList<T>::clear()
	{
		//temp Node to loop through elements, starting with first
		Node<T>* temp = _sentinelNode->getNextNode();

		//loop through all Nodes
		while (temp != _sentinelNode)
		{
			Node<T>* nextNode = temp->getNextNode();
			delete temp; //remove the Node
			temp = nextNode; //move onto the next
		} //end while

		//set sentinel to point to itself again
		_sentinelNode->setNextNode(_sentinelNode);
		_sentinelNode->setPrevNode(_sentinelNode);
	} //end clear

	/**
	 * Iterates through the LinkedList, counting each iteration
	 * until the end is reached, and then returns the number of
	 * iterations.
	 **/
	template <class T>
	int LinkedList<T>::getSize() const
	{
		int count = 0; //count number of elements

		//iterate through all elements and count each incrementation
		for (Iterator<T> it = begin(); it != end(); ++it)
			count++;

		return count;
	} //end getSize

	/**
	 * Returns the maximum possible capacity of a LinkedList.
	 **/
	template <class T>
	const int LinkedList<T>::getMaxSize() const
	{
		return MAX_CAPACITY;
	} //end getMaxSize

	/**
	 * Returns true if the LinkedList contains no elements. If
	 * the sentinel Node is not attached to any other Nodes, then
	 * the LinkedList must be empty.
	 **/
	template <class T>
	bool LinkedList<T>::isEmpty() const
	{
		//if the sentinel points to itself, there are no items
		return (_sentinelNode->getNextNode() == _sentinelNode);
	} //end isEmpty

	/**
	 * Checks to see if the LinkedList's current size is equal
	 * to the maximum possible capacity. If true, then the
	 * LinkedList is full and can no longer hold any items.
	 **/
	template <class T>
	bool LinkedList<T>::isFull() const
	{
		return (getSize() == getMaxSize());
	} //end isFull

	/**
	 * Overloads the assignment operator (=). Clears the LinkedList,
	 * then creates and returns a copy of the specified original,
	 * using the copy constructor.
	 **/
	template <class T>
	LinkedList<T> LinkedList<T>::operator=(const LinkedList<T>& original)
	{
		clear(); //clear list

		LinkedList<T> newList(original); //create copy of passed original

		return newList;
	} //end = assignment operator overload

	/**
	 * Overloads the compound addition operator (+=). Takes the contents
	 * of a specified list and pushes those contents to the back of this
	 * one, then returning this object.
	 **/
	template <class T>
	LinkedList<T>& LinkedList<T>::operator+=(const LinkedList<T>& addend)
	{
		//iterate through other list
		//(auto keyword infers return type and makes declared variable that type)
		for (auto it = addend.begin(); it != addend.end(); ++it)
			pushBack(*it); //push that list's items onto this list

		return *this;
	} //end += compound addition operator overload

	/**
	 * Overloads the compound subtraction operator (-=). Removes any
	 * elements from this list that it shares in common with a specified
	 * other list.
	 **/
	template <class T>
	LinkedList<T>& LinkedList<T>::operator-=(const LinkedList<T>& subtrahend)
	{
		//iterate through other list
		//(auto keyword infers return type and makes declared variable that type)
		for (auto it = subtrahend.begin(); it != subtrahend.end(); ++it)
			remove(*it); //remove the first instance of common element

		return *this;
	} //end -= compound subtraction operator overload
} //end namespace
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>

#include <osg/Notify>

#include <stdio.h>

using namespace std;
using namespace osgDB;

Output::Output()
{
    init();
}

Output::Output(const char* name) : ofstream(name)
{
    init();
    _filename = name;
}

Output::Output(const Output&) : ofstream() {}

Output& Output::operator = (const Output&) { return *this; }

Output::~Output()
{
}

void Output::init()
{
    _indent = 0;
    _indentStep = 2;
    _numIndicesPerLine = 10;
    _pathNameHint = AS_IS;
}

void Output::open(const char *name)
{
    init();
    ofstream::open(name);
    _filename = name;
}

// Comment out to avoid compile errors under new compilers, the int mode
// is now a replaced by a class to wrap the mode.
// This method is not used right now to hopefully nobody will miss it...
// Jan 2002.
// void Output::open(const char *name,int mode)
// {
//     init();
//     ofstream::open(name,mode);
//     _filename = name;
// }

Output& Output::indent()
{
    for(int i=0;i<_indent;++i) *this<<' ';
    return *this;
}

void Output::moveIn()
{
    _indent += _indentStep;
}

void Output::moveOut()
{
    _indent -= _indentStep;
    if (_indent<0) _indent=0;
}

std::string Output::wrapString(const std::string& str)
{
    std::string newstring;
    newstring += '"';
    for(unsigned int i=0;i<str.size();++i)
    {
    	if (str[i]=='"')
	{
	    newstring += '\\';
	    newstring += '"';
	}
	else newstring += (str[i]);
    }
    newstring += '"';
    return newstring;
}

bool Output::writeObject(const osg::Object& obj)
{
    return Registry::instance()->writeObject(obj,*this);
}

bool Output::getUniqueIDForObject(const osg::Object* obj,std::string& uniqueID)
{
    UniqueIDToLabelMapping::iterator fitr = _objectToUniqueIDMap.find(obj);
    if (fitr != _objectToUniqueIDMap.end())
    {
        uniqueID = (*fitr).second;
        return true;
    }
    else return false;
}

bool Output::createUniqueIDForObject(const osg::Object* obj,std::string& uniqueID)
{
    char str[256];
    sprintf(str,"%s_%i",obj->className(),(unsigned int)_objectToUniqueIDMap.size());
    uniqueID = str;
    return true;
}

bool Output::registerUniqueIDForObject(const osg::Object* obj,std::string& uniqueID)
{
    _objectToUniqueIDMap[obj] = uniqueID;
    return true;
}

const std::string Output::getFileNameForOutput(const std::string& filename) const
{
    switch(_pathNameHint)
    {
    case(FULL_PATH):
        {
            // need to think about how best to implement this first...
            osg::notify(osg::WARN)<<"Warning: Output::getFileNameForOutput() does not support FULL_PATH yet."<< std::endl;
            return filename;
        }
    case(RELATIVE_PATH):
        {
            // need to think about how best to implement this as well...
            osg::notify(osg::WARN)<<"Warning: Output::getFileNameForOutput() does not support RELATIVE_PATH yet."<< std::endl;
            return filename;
        }
    case(FILENAME_ONLY):
        // this one is straight forward.
        return getSimpleFileName(filename);
    case(AS_IS):
    default:
        // and this one is even more trivial.
        return filename;
    }
}
<commit_msg>Removed redundent const<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>

#include <osg/Notify>

#include <stdio.h>

using namespace std;
using namespace osgDB;

Output::Output()
{
    init();
}

Output::Output(const char* name) : ofstream(name)
{
    init();
    _filename = name;
}

Output::Output(const Output&) : ofstream() {}

Output& Output::operator = (const Output&) { return *this; }

Output::~Output()
{
}

void Output::init()
{
    _indent = 0;
    _indentStep = 2;
    _numIndicesPerLine = 10;
    _pathNameHint = AS_IS;
}

void Output::open(const char *name)
{
    init();
    ofstream::open(name);
    _filename = name;
}

// Comment out to avoid compile errors under new compilers, the int mode
// is now a replaced by a class to wrap the mode.
// This method is not used right now to hopefully nobody will miss it...
// Jan 2002.
// void Output::open(const char *name,int mode)
// {
//     init();
//     ofstream::open(name,mode);
//     _filename = name;
// }

Output& Output::indent()
{
    for(int i=0;i<_indent;++i) *this<<' ';
    return *this;
}

void Output::moveIn()
{
    _indent += _indentStep;
}

void Output::moveOut()
{
    _indent -= _indentStep;
    if (_indent<0) _indent=0;
}

std::string Output::wrapString(const std::string& str)
{
    std::string newstring;
    newstring += '"';
    for(unsigned int i=0;i<str.size();++i)
    {
    	if (str[i]=='"')
	{
	    newstring += '\\';
	    newstring += '"';
	}
	else newstring += (str[i]);
    }
    newstring += '"';
    return newstring;
}

bool Output::writeObject(const osg::Object& obj)
{
    return Registry::instance()->writeObject(obj,*this);
}

bool Output::getUniqueIDForObject(const osg::Object* obj,std::string& uniqueID)
{
    UniqueIDToLabelMapping::iterator fitr = _objectToUniqueIDMap.find(obj);
    if (fitr != _objectToUniqueIDMap.end())
    {
        uniqueID = (*fitr).second;
        return true;
    }
    else return false;
}

bool Output::createUniqueIDForObject(const osg::Object* obj,std::string& uniqueID)
{
    char str[256];
    sprintf(str,"%s_%i",obj->className(),(unsigned int)_objectToUniqueIDMap.size());
    uniqueID = str;
    return true;
}

bool Output::registerUniqueIDForObject(const osg::Object* obj,std::string& uniqueID)
{
    _objectToUniqueIDMap[obj] = uniqueID;
    return true;
}

std::string Output::getFileNameForOutput(const std::string& filename) const
{
    switch(_pathNameHint)
    {
    case(FULL_PATH):
        {
            // need to think about how best to implement this first...
            osg::notify(osg::WARN)<<"Warning: Output::getFileNameForOutput() does not support FULL_PATH yet."<< std::endl;
            return filename;
        }
    case(RELATIVE_PATH):
        {
            // need to think about how best to implement this as well...
            osg::notify(osg::WARN)<<"Warning: Output::getFileNameForOutput() does not support RELATIVE_PATH yet."<< std::endl;
            return filename;
        }
    case(FILENAME_ONLY):
        // this one is straight forward.
        return getSimpleFileName(filename);
    case(AS_IS):
    default:
        // and this one is even more trivial.
        return filename;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2010 MQWeb - Franky Braem
 *
 * Licensed under the EUPL, Version 1.1 or – as soon they
 * will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the
 * Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 */
#include <string.h> // For memcpy
#include <cmqc.h>

#include "Poco/DateTimeParser.h"
#include "MQ/PCF.h"

namespace MQ
{

PCF::PCF(bool zos)
	: Message()
	, _zos(zos)
{
}

PCF::PCF(int cmd, bool zos)
	: Message()
	, _zos(zos)
{
	setFormat(MQFMT_ADMIN);
	setType(MQMT_REQUEST);
	setPersistence(MQPER_NOT_PERSISTENT);
	buffer().resize(MQCFH_STRUC_LENGTH);
	MQCFH* header = (MQCFH*)(MQBYTE*) &buffer()[0];
	header->StrucLength    = MQCFH_STRUC_LENGTH;
	if ( _zos )
	{
		header->Type    = MQCFT_COMMAND_XR;
		header->Version = MQCFH_VERSION_3;
	}
	else
	{
		header->Type       = (MQLONG) MQCFT_COMMAND;
		header->Version    = MQCFH_VERSION_1;
	}
	header->Command        = cmd;
	header->MsgSeqNumber   = MQCFC_LAST;
	header->Control        = MQCFC_LAST;
	header->ParameterCount = 0;
}

PCF::~PCF()
{
}

void PCF::init()
{
	MQCFH* header = (MQCFH*)(MQBYTE*) &(buffer()[0]);
	int pos = MQCFH_STRUC_LENGTH;
	for(int i = 0; i < header->ParameterCount; i++)
	{
		MQLONG *pcfType = (MQLONG*) &buffer()[pos];
		_pointers[pcfType[2]] = pos;
		pos += pcfType[1];
	}
}

std::string PCF::getParameterString(MQLONG parameter) const
{
	MQCFH* header = (MQCFH*)(MQBYTE*) &(buffer()[0]);
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_STRING )
	{
		MQCFST* pcfParam = (MQCFST*) &buffer()[it->second];
		std::string result(pcfParam->String, pcfParam->StringLength);
		return Poco::trimRightInPlace(result);
	}
	else if ( *pcfType == MQCFT_BYTE_STRING )
	{
		MQCFBS* pcfParam = (MQCFBS*) &buffer()[it->second];
		return Message::getBufferAsHex(pcfParam->String, pcfParam->StringLength);
	}

	throw Poco::BadCastException(parameter);
}

BufferPtr PCF::getParameterByteString(MQLONG parameter) const
{
	MQCFH* header = (MQCFH*)(MQBYTE*) &(buffer()[0]);
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_BYTE_STRING )
	{
		MQCFBS* pcfParam = (MQCFBS*) &buffer()[it->second];
		return new Buffer(pcfParam->String, pcfParam->StringLength);
	}

	throw Poco::BadCastException(parameter);
}

std::string PCF::optParameterString(MQLONG parameter, const std::string& def) const
{
	std::string result = def;

	try
	{
		result = getParameterString(parameter);
	}
	catch(...)
	{
	}

	return result;
}

Poco::DateTime PCF::getParameterDate(MQLONG dateParameter, MQLONG timeParameter) const
{
	std::string dateValue = getParameterString(dateParameter);
	Poco::trimRightInPlace(dateValue);
	std::string timeValue = getParameterString(timeParameter);
	Poco::trimRightInPlace(timeValue);
	dateValue += timeValue;
	if ( ! dateValue.empty() )
	{
		Poco::DateTime dateTime;
		int timeZone;
		Poco::DateTimeParser::parse("%Y%n%e%H%M%S", dateValue, dateTime, timeZone);
		return dateTime;
	}
	return Poco::DateTime();
}

MQLONG PCF::getParameterNum(MQLONG parameter) const
{
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_INTEGER )
	{
		MQCFIN* pcfParam = (MQCFIN*) &buffer()[it->second];
		return pcfParam->Value;
	}

	throw Poco::BadCastException(parameter);
}

std::vector<MQLONG> PCF::getParameterNumList(MQLONG parameter) const
{
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_INTEGER_LIST )
	{
		std::vector<MQLONG> list;
		MQCFIL* pcfParam = (MQCFIL*) &buffer()[it->second];
		for(int i = 0; i < pcfParam->Count; ++i)
		{
			list.push_back(pcfParam->Values[i]);
		}
		return list;
	}

	throw Poco::BadCastException(parameter);
}

std::vector<std::string> PCF::getParameterStringList(MQLONG parameter) const
{
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_STRING_LIST )
	{
		std::vector<std::string> list;
		MQCFSL* pcfParam = (MQCFSL*) &buffer()[it->second];
		for(int i = 0; i < pcfParam->Count; ++i)
		{
			std::string result(pcfParam->Strings, i * pcfParam->StringLength, pcfParam->StringLength);
			Poco::trimRightInPlace(result);
			list.push_back(result);
		}
		return list;
	}

	throw Poco::BadCastException(parameter);
}

MQLONG PCF::optParameterNum(MQLONG parameter, MQLONG def) const
{
	MQLONG result = def;
	try
	{
		result = getParameterNum(parameter);
	}
	catch(...)
	{
	}
	return result;
}

void PCF::addParameter(MQLONG parameter, const std::string& value)
{
	MQLONG structLength = ((MQCFST_STRUC_LENGTH_FIXED + value.length()) / 4 + 1) * 4;
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + structLength);
	MQCFST* pcfParam = (MQCFST*) &buffer()[_pointers[parameter]];
	pcfParam->Type           = MQCFT_STRING;
	pcfParam->StrucLength    = structLength;
	pcfParam->Parameter      = parameter;
	pcfParam->CodedCharSetId = MQCCSI_DEFAULT;
	pcfParam->StringLength   = value.length();
	memcpy(pcfParam->String, value.c_str(), pcfParam->StringLength);
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addParameter(MQLONG parameter, MQLONG value)
{
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + MQCFIN_STRUC_LENGTH);
	MQCFIN* pcfParam = (MQCFIN*) &buffer()[_pointers[parameter]];
	pcfParam->Type        = MQCFT_INTEGER;
	pcfParam->StrucLength = MQCFIN_STRUC_LENGTH;
	pcfParam->Parameter   = parameter;
	pcfParam->Value       = value;
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addParameter(MQLONG parameter, BufferPtr value)
{
	MQLONG structLength = ((MQCFST_STRUC_LENGTH_FIXED + value->sizeBytes()) / 4 + 1) * 4;
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + structLength);
	MQCFBS* pcfParam = (MQCFBS*) &buffer()[_pointers[parameter]];
	pcfParam->Type           = MQCFT_BYTE_STRING;
	pcfParam->StrucLength    = structLength;
	pcfParam->Parameter      = parameter;
	pcfParam->StringLength   = value->sizeBytes();
	memcpy(pcfParam->String, value->begin(), pcfParam->StringLength);
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addParameterList(MQLONG parameter, MQLONG *values, unsigned int count)
{
	int strucLength = MQCFIL_STRUC_LENGTH_FIXED + count * sizeof(MQLONG);
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + strucLength);
	MQCFIL *pcfIntegerList = (MQCFIL *) &buffer()[_pointers[parameter]];
	pcfIntegerList->Count       = count;
	pcfIntegerList->Type        = MQCFT_INTEGER_LIST;
	pcfIntegerList->StrucLength = strucLength;
	pcfIntegerList->Parameter   = parameter;
	for(int i = 0; i < count; ++i) pcfIntegerList->Values[i] = values[i];
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addFilter(MQLONG parameter, MQLONG op, const std::string& value)
{
	MQLONG strucLength = ((MQCFSF_STRUC_LENGTH_FIXED + value.length()) / 4 + 1) * 4;
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + strucLength);
	MQCFSF* pcfFilter = (MQCFSF*) &buffer()[_pointers[parameter]];
	pcfFilter->Type              = MQCFT_STRING_FILTER;
	pcfFilter->StrucLength       = strucLength;
	pcfFilter->Parameter         = parameter;
	pcfFilter->Operator          = op;
	pcfFilter->CodedCharSetId    = MQCCSI_DEFAULT;
	pcfFilter->FilterValueLength = value.length();
	memcpy(pcfFilter->FilterValue, value.c_str(), pcfFilter->FilterValueLength);
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addFilter(MQLONG parameter, MQLONG op, MQLONG value)
{
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + MQCFIF_STRUC_LENGTH);
	MQCFIF* pcfFilter = (MQCFIF*) &buffer()[_pointers[parameter]];
	pcfFilter->Type              = MQCFT_INTEGER_FILTER;
	pcfFilter->StrucLength       = MQCFIF_STRUC_LENGTH;
	pcfFilter->Parameter         = parameter;
	pcfFilter->Operator          = op;
	pcfFilter->FilterValue       = value;
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

std::vector<MQLONG> PCF::getParameters() const
{
	std::vector<MQLONG> parameters;
	for(std::map<MQLONG, int>::const_iterator it = _pointers.begin(); it != _pointers.end(); it++)
	{
		MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
		parameters.push_back(pcfType[2]);
	}
	return parameters;
}

} // Namespace MQ
<commit_msg>Resize string to 0 when a parameter value starts with a null byte<commit_after>/*
 * Copyright 2010 MQWeb - Franky Braem
 *
 * Licensed under the EUPL, Version 1.1 or – as soon they
 * will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the
 * Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 */
#include <string.h> // For memcpy
#include <cmqc.h>

#include "Poco/DateTimeParser.h"
#include "MQ/PCF.h"

namespace MQ
{

PCF::PCF(bool zos)
	: Message()
	, _zos(zos)
{
}

PCF::PCF(int cmd, bool zos)
	: Message()
	, _zos(zos)
{
	setFormat(MQFMT_ADMIN);
	setType(MQMT_REQUEST);
	setPersistence(MQPER_NOT_PERSISTENT);
	buffer().resize(MQCFH_STRUC_LENGTH);
	MQCFH* header = (MQCFH*)(MQBYTE*) &buffer()[0];
	header->StrucLength    = MQCFH_STRUC_LENGTH;
	if ( _zos )
	{
		header->Type    = MQCFT_COMMAND_XR;
		header->Version = MQCFH_VERSION_3;
	}
	else
	{
		header->Type       = (MQLONG) MQCFT_COMMAND;
		header->Version    = MQCFH_VERSION_1;
	}
	header->Command        = cmd;
	header->MsgSeqNumber   = MQCFC_LAST;
	header->Control        = MQCFC_LAST;
	header->ParameterCount = 0;
}

PCF::~PCF()
{
}

void PCF::init()
{
	MQCFH* header = (MQCFH*)(MQBYTE*) &(buffer()[0]);
	int pos = MQCFH_STRUC_LENGTH;
	for(int i = 0; i < header->ParameterCount; i++)
	{
		MQLONG *pcfType = (MQLONG*) &buffer()[pos];
		_pointers[pcfType[2]] = pos;
		pos += pcfType[1];
	}
}

std::string PCF::getParameterString(MQLONG parameter) const
{
	MQCFH* header = (MQCFH*)(MQBYTE*) &(buffer()[0]);
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_STRING )
	{
		MQCFST* pcfParam = (MQCFST*) &buffer()[it->second];
		std::string result(pcfParam->String, pcfParam->StringLength);
		if ( result[0] == '\0' ) result.resize(0);
		return Poco::trimRightInPlace(result);
	}
	else if ( *pcfType == MQCFT_BYTE_STRING )
	{
		MQCFBS* pcfParam = (MQCFBS*) &buffer()[it->second];
		return Message::getBufferAsHex(pcfParam->String, pcfParam->StringLength);
	}

	throw Poco::BadCastException(parameter);
}

BufferPtr PCF::getParameterByteString(MQLONG parameter) const
{
	MQCFH* header = (MQCFH*)(MQBYTE*) &(buffer()[0]);
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_BYTE_STRING )
	{
		MQCFBS* pcfParam = (MQCFBS*) &buffer()[it->second];
		return new Buffer(pcfParam->String, pcfParam->StringLength);
	}

	throw Poco::BadCastException(parameter);
}

std::string PCF::optParameterString(MQLONG parameter, const std::string& def) const
{
	std::string result = def;

	try
	{
		result = getParameterString(parameter);
	}
	catch(...)
	{
	}

	return result;
}

Poco::DateTime PCF::getParameterDate(MQLONG dateParameter, MQLONG timeParameter) const
{
	std::string dateValue = getParameterString(dateParameter);
	Poco::trimRightInPlace(dateValue);
	std::string timeValue = getParameterString(timeParameter);
	Poco::trimRightInPlace(timeValue);
	dateValue += timeValue;
	if ( ! dateValue.empty() )
	{
		Poco::DateTime dateTime;
		int timeZone;
		Poco::DateTimeParser::parse("%Y%n%e%H%M%S", dateValue, dateTime, timeZone);
		return dateTime;
	}
	return Poco::DateTime();
}

MQLONG PCF::getParameterNum(MQLONG parameter) const
{
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_INTEGER )
	{
		MQCFIN* pcfParam = (MQCFIN*) &buffer()[it->second];
		return pcfParam->Value;
	}

	throw Poco::BadCastException(parameter);
}

std::vector<MQLONG> PCF::getParameterNumList(MQLONG parameter) const
{
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_INTEGER_LIST )
	{
		std::vector<MQLONG> list;
		MQCFIL* pcfParam = (MQCFIL*) &buffer()[it->second];
		for(int i = 0; i < pcfParam->Count; ++i)
		{
			list.push_back(pcfParam->Values[i]);
		}
		return list;
	}

	throw Poco::BadCastException(parameter);
}

std::vector<std::string> PCF::getParameterStringList(MQLONG parameter) const
{
	std::map<MQLONG, int>::const_iterator it = _pointers.find(parameter);
	if ( it == _pointers.end() )
		throw Poco::NotFoundException(parameter);

	MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
	if ( *pcfType == MQCFT_STRING_LIST )
	{
		std::vector<std::string> list;
		MQCFSL* pcfParam = (MQCFSL*) &buffer()[it->second];
		for(int i = 0; i < pcfParam->Count; ++i)
		{
			std::string result(pcfParam->Strings, i * pcfParam->StringLength, pcfParam->StringLength);
			Poco::trimRightInPlace(result);
			list.push_back(result);
		}
		return list;
	}

	throw Poco::BadCastException(parameter);
}

MQLONG PCF::optParameterNum(MQLONG parameter, MQLONG def) const
{
	MQLONG result = def;
	try
	{
		result = getParameterNum(parameter);
	}
	catch(...)
	{
	}
	return result;
}

void PCF::addParameter(MQLONG parameter, const std::string& value)
{
	MQLONG structLength = ((MQCFST_STRUC_LENGTH_FIXED + value.length()) / 4 + 1) * 4;
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + structLength);
	MQCFST* pcfParam = (MQCFST*) &buffer()[_pointers[parameter]];
	pcfParam->Type           = MQCFT_STRING;
	pcfParam->StrucLength    = structLength;
	pcfParam->Parameter      = parameter;
	pcfParam->CodedCharSetId = MQCCSI_DEFAULT;
	pcfParam->StringLength   = value.length();
	memcpy(pcfParam->String, value.c_str(), pcfParam->StringLength);
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addParameter(MQLONG parameter, MQLONG value)
{
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + MQCFIN_STRUC_LENGTH);
	MQCFIN* pcfParam = (MQCFIN*) &buffer()[_pointers[parameter]];
	pcfParam->Type        = MQCFT_INTEGER;
	pcfParam->StrucLength = MQCFIN_STRUC_LENGTH;
	pcfParam->Parameter   = parameter;
	pcfParam->Value       = value;
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addParameter(MQLONG parameter, BufferPtr value)
{
	MQLONG structLength = ((MQCFST_STRUC_LENGTH_FIXED + value->sizeBytes()) / 4 + 1) * 4;
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + structLength);
	MQCFBS* pcfParam = (MQCFBS*) &buffer()[_pointers[parameter]];
	pcfParam->Type           = MQCFT_BYTE_STRING;
	pcfParam->StrucLength    = structLength;
	pcfParam->Parameter      = parameter;
	pcfParam->StringLength   = value->sizeBytes();
	memcpy(pcfParam->String, value->begin(), pcfParam->StringLength);
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addParameterList(MQLONG parameter, MQLONG *values, unsigned int count)
{
	int strucLength = MQCFIL_STRUC_LENGTH_FIXED + count * sizeof(MQLONG);
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + strucLength);
	MQCFIL *pcfIntegerList = (MQCFIL *) &buffer()[_pointers[parameter]];
	pcfIntegerList->Count       = count;
	pcfIntegerList->Type        = MQCFT_INTEGER_LIST;
	pcfIntegerList->StrucLength = strucLength;
	pcfIntegerList->Parameter   = parameter;
	for(int i = 0; i < count; ++i) pcfIntegerList->Values[i] = values[i];
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addFilter(MQLONG parameter, MQLONG op, const std::string& value)
{
	MQLONG strucLength = ((MQCFSF_STRUC_LENGTH_FIXED + value.length()) / 4 + 1) * 4;
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + strucLength);
	MQCFSF* pcfFilter = (MQCFSF*) &buffer()[_pointers[parameter]];
	pcfFilter->Type              = MQCFT_STRING_FILTER;
	pcfFilter->StrucLength       = strucLength;
	pcfFilter->Parameter         = parameter;
	pcfFilter->Operator          = op;
	pcfFilter->CodedCharSetId    = MQCCSI_DEFAULT;
	pcfFilter->FilterValueLength = value.length();
	memcpy(pcfFilter->FilterValue, value.c_str(), pcfFilter->FilterValueLength);
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

void PCF::addFilter(MQLONG parameter, MQLONG op, MQLONG value)
{
	_pointers[parameter] = buffer().size();
	buffer().resize(buffer().size() + MQCFIF_STRUC_LENGTH);
	MQCFIF* pcfFilter = (MQCFIF*) &buffer()[_pointers[parameter]];
	pcfFilter->Type              = MQCFT_INTEGER_FILTER;
	pcfFilter->StrucLength       = MQCFIF_STRUC_LENGTH;
	pcfFilter->Parameter         = parameter;
	pcfFilter->Operator          = op;
	pcfFilter->FilterValue       = value;
	MQCFH* header = (MQCFH*) (MQBYTE*) &buffer()[0];
	header->ParameterCount++;
}

std::vector<MQLONG> PCF::getParameters() const
{
	std::vector<MQLONG> parameters;
	for(std::map<MQLONG, int>::const_iterator it = _pointers.begin(); it != _pointers.end(); it++)
	{
		MQLONG *pcfType = (MQLONG*) &buffer()[it->second];
		parameters.push_back(pcfType[2]);
	}
	return parameters;
}

} // Namespace MQ
<|endoftext|>


<commit_before>#include "MainWindow.h"

#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>

#include <assert.h>

namespace
{
Chip8::byte_t qtToEmu(int key, bool *ok)
{
	assert(ok != nullptr);
	(*ok) = true;
	switch (key)
	{
	case Qt::Key_1: return 0x1;
	case Qt::Key_2: return 0x2;
	case Qt::Key_3: return 0x3;
	case Qt::Key_4: return 0xC;
	case Qt::Key_Q: return 0x4;
	case Qt::Key_W: return 0x5;
	case Qt::Key_E: return 0x6;
	case Qt::Key_R: return 0xD;
	case Qt::Key_A: return 0x7;
	case Qt::Key_S: return 0x8;
	case Qt::Key_D: return 0x9;
	case Qt::Key_F: return 0xE;
	case Qt::Key_Z: return 0xA;
	case Qt::Key_X: return 0x0;
	case Qt::Key_C: return 0xB;
	case Qt::Key_V: return 0xF;
	default: (*ok) = false; return 0x0;
	}
}
}

namespace Chip8GUI
{
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
	ui.setupUi(this);

	connect(ui.actionOpen, &QAction::triggered, this, &MainWindow::openROM);
	connect(ui.actionClose, &QAction::triggered, this, &MainWindow::closeROM);

	connect(ui.actionAbout, &QAction::triggered, this, &MainWindow::about);

	executionTimer.setInterval(0);
	connect(&executionTimer, &QTimer::timeout, this, &MainWindow::execute);

	ui.display->setPixels(emu.getDisplay().getPixels());
}
MainWindow::~MainWindow()
{
}

void MainWindow::openROM()
{
	QString filename = QFileDialog::getOpenFileName(this, tr("Open..."), QString(), tr("Chip-8 ROM (*.ch8);;All files (*.*)"));
	if (filename.isNull())
		return;

	if (emu.open(filename.toStdString()))
	{
		elapsedTimer.start();
		executionTimer.start();
	}
}
void MainWindow::closeROM()
{
	emu.close();

	executionTimer.stop();
}

void MainWindow::about()
{
	QMessageBox::about(this, tr("About Chip8Emu"), tr("Chip-8 Emulator"));
}

void MainWindow::execute()
{
	float elapsedSeconds = static_cast<float>(elapsedTimer.restart()) / 1000.f;
	emu.step(elapsedSeconds);

	ui.display->update();
}

void MainWindow::keyPressEvent(QKeyEvent *e)
{
	bool ok;
	Chip8::byte_t emuKey = qtToEmu(e->key(), &ok);
	if (!ok)
	{
		return QMainWindow::keyPressEvent(e);
	}

	emu.getInput().setPressed(emuKey, true);
}
void MainWindow::keyReleaseEvent(QKeyEvent *e)
{
	bool ok;
	Chip8::byte_t emuKey = qtToEmu(e->key(), &ok);
	if (!ok)
	{
		return QMainWindow::keyReleaseEvent(e);
	}

	emu.getInput().setPressed(emuKey, false);
}
}
<commit_msg>The display is updated one last time when closing a ROM<commit_after>#include "MainWindow.h"

#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>

#include <assert.h>

namespace
{
Chip8::byte_t qtToEmu(int key, bool *ok)
{
	assert(ok != nullptr);
	(*ok) = true;
	switch (key)
	{
	case Qt::Key_1: return 0x1;
	case Qt::Key_2: return 0x2;
	case Qt::Key_3: return 0x3;
	case Qt::Key_4: return 0xC;
	case Qt::Key_Q: return 0x4;
	case Qt::Key_W: return 0x5;
	case Qt::Key_E: return 0x6;
	case Qt::Key_R: return 0xD;
	case Qt::Key_A: return 0x7;
	case Qt::Key_S: return 0x8;
	case Qt::Key_D: return 0x9;
	case Qt::Key_F: return 0xE;
	case Qt::Key_Z: return 0xA;
	case Qt::Key_X: return 0x0;
	case Qt::Key_C: return 0xB;
	case Qt::Key_V: return 0xF;
	default: (*ok) = false; return 0x0;
	}
}
}

namespace Chip8GUI
{
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
	ui.setupUi(this);

	connect(ui.actionOpen, &QAction::triggered, this, &MainWindow::openROM);
	connect(ui.actionClose, &QAction::triggered, this, &MainWindow::closeROM);

	connect(ui.actionAbout, &QAction::triggered, this, &MainWindow::about);

	executionTimer.setInterval(0);
	connect(&executionTimer, &QTimer::timeout, this, &MainWindow::execute);

	ui.display->setPixels(emu.getDisplay().getPixels());
}
MainWindow::~MainWindow()
{
}

void MainWindow::openROM()
{
	QString filename = QFileDialog::getOpenFileName(this, tr("Open..."), QString(), tr("Chip-8 ROM (*.ch8);;All files (*.*)"));
	if (filename.isNull())
		return;

	if (emu.open(filename.toStdString()))
	{
		elapsedTimer.start();
		executionTimer.start();
	}
}
void MainWindow::closeROM()
{
	emu.close();
	ui.display->update();

	executionTimer.stop();
}

void MainWindow::about()
{
	QMessageBox::about(this, tr("About Chip8Emu"), tr("Chip-8 Emulator"));
}

void MainWindow::execute()
{
	float elapsedSeconds = static_cast<float>(elapsedTimer.restart()) / 1000.f;
	emu.step(elapsedSeconds);

	ui.display->update();
}

void MainWindow::keyPressEvent(QKeyEvent *e)
{
	bool ok;
	Chip8::byte_t emuKey = qtToEmu(e->key(), &ok);
	if (!ok)
	{
		return QMainWindow::keyPressEvent(e);
	}

	emu.getInput().setPressed(emuKey, true);
}
void MainWindow::keyReleaseEvent(QKeyEvent *e)
{
	bool ok;
	Chip8::byte_t emuKey = qtToEmu(e->key(), &ok);
	if (!ok)
	{
		return QMainWindow::keyReleaseEvent(e);
	}

	emu.getInput().setPressed(emuKey, false);
}
}
<|endoftext|>


<commit_before>#include "MapManager.h"

#include "UnitManager.h"

//#include <algorithm>

BWAPI::TilePosition startPos;

Neolib::MapManager mapManager;

struct sortLocations {
	static bool fromStartPos(const BWEM::Base *lhs, const BWEM::Base *rhs) {
		return lhs->Location().getApproxDistance(startPos) < rhs->Location().getApproxDistance(startPos);
	}
};

namespace Neolib {

	void MapManager::init() {
		BWEM::Map::Instance().Initialize();
		BWEM::Map::Instance().EnableAutomaticPathAnalysis();

		for (auto &a : BWEM::Map::Instance().Areas())
			for (auto &b : a.Bases())
				allBases.push_back(&b);

		for (auto &b : allBases) {
			if (BWAPI::Broodwar->isVisible(b->Location())) {
				startPos = b->Location();
				std::sort(allBases.begin(), allBases.end(), sortLocations::fromStartPos);
			}
		}
	}

	void MapManager::onFrame() {
		for (auto it = unexploredBases.begin(); it != unexploredBases.end(); ++it) {
			if (BWAPI::Broodwar->isVisible((*it)->Location())) {
				unexploredBases.erase(it);
				break;
			}
		}
	}

	const std::vector <const BWEM::Base*> MapManager::getAllBases() const {
		return allBases;
	}
	const std::set    <const BWEM::Base*> MapManager::getUnexploredBases() const {
		return unexploredBases;
	}

	const BWAPI::TilePosition MapManager::getNextBasePosition() const {
		for (auto &b : allBases) {
			if (BWAPI::Broodwar->canBuildHere(b->Location(), BWAPI::UnitTypes::Terran_Command_Center)) {
				for (auto &eu : unitManager.getKnownEnemies())
					if (eu.second.first.getApproxDistance(BWAPI::Position(b->Location())) < 1000)
						goto skiplocation;

				return b->Location();
				skiplocation:;
			}
		}

		return BWAPI::TilePosition(-1, -1);
	}
}
<commit_msg>Scans for expansions<commit_after>#include "MapManager.h"

#include "UnitManager.h"
#include "DetectionManager.h"

//#include <algorithm>

BWAPI::TilePosition startPos;

Neolib::MapManager mapManager;

struct sortLocations {
	static bool fromStartPos(const BWEM::Base *lhs, const BWEM::Base *rhs) {
		return lhs->Location().getApproxDistance(startPos) < rhs->Location().getApproxDistance(startPos);
	}
};

namespace Neolib {

	void MapManager::init() {
		BWEM::Map::Instance().Initialize();
		BWEM::Map::Instance().EnableAutomaticPathAnalysis();

		for (auto &a : BWEM::Map::Instance().Areas())
			for (auto &b : a.Bases())
				allBases.push_back(&b);

		for (auto &b : allBases) {
			if (BWAPI::Broodwar->isVisible(b->Location())) {
				startPos = b->Location();
				std::sort(allBases.begin(), allBases.end(), sortLocations::fromStartPos);
			}
		}
	}

	void MapManager::onFrame() {
		for (auto it = unexploredBases.begin(); it != unexploredBases.end(); ++it) {
			if (BWAPI::Broodwar->isVisible((*it)->Location())) {
				unexploredBases.erase(it);
				break;
			}
		}
	}

	const std::vector <const BWEM::Base*> MapManager::getAllBases() const {
		return allBases;
	}
	const std::set    <const BWEM::Base*> MapManager::getUnexploredBases() const {
		return unexploredBases;
	}

	const BWAPI::TilePosition MapManager::getNextBasePosition() const {
		for (auto &b : allBases) {
			if (!BWAPI::Broodwar->isExplored(b->Location()))
				detectionManager.requestDetection((BWAPI::Position)b->Location());
			if (BWAPI::Broodwar->canBuildHere(b->Location(), BWAPI::UnitTypes::Terran_Command_Center)) {
				for (auto &eu : unitManager.getKnownEnemies())
					if (eu.second.first.getApproxDistance(BWAPI::Position(b->Location())) < 1000)
						goto skiplocation;

				return b->Location();
				skiplocation:;
			}
		}

		return BWAPI::TilePosition(-1, -1);
	}
}
<|endoftext|>


<commit_before>/*
 * This file is part of kpeople
 *
 * Copyright (C) 2010-2011 Collabora Ltd. <info@collabora.co.uk>
 *   @author George Goldberg <george.goldberg@collabora.co.uk>
 *   @author Martin Klapetek <martin.klapetek@gmail.com>
 *
 * Copyright (C) 2012  Aleix Pol Gonzalez <aleixpol@blue-systems.com>
 *
 * 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
 */

#include "person-cache.h"

#include <KDebug>
#include <KGlobal>
#include <KUrl>

#include <QtCore/QHash>

#include <Soprano/Query/QueryLanguage>
#include <Soprano/QueryResultIterator>
#include <Soprano/Model>

#include <Nepomuk/ResourceManager>
#include <Nepomuk/Variant>

#include <Nepomuk/Vocabulary/PIMO>
#include <Nepomuk/Vocabulary/NCO>
#include <Soprano/Vocabulary/NAO>

#include "persons-model.h"
#include "persons-model-item.h"
#include "persons-model-contact-item.h"

K_GLOBAL_STATIC(PersonCache, s_globalPersonCache)

/******************************** PersonCache::Private ********************************************/

class PersonCachePrivate {

protected:
    Q_DECLARE_PUBLIC(PersonCache);
    PersonCache * const q_ptr;

public:
    explicit PersonCachePrivate(PersonCache *q)
    : q_ptr(q)
    { }

    virtual ~PersonCachePrivate()
    { }

    QHash<QUrl, PersonsModelItem*> persons;
    QList<QUrl> allRequestedKeys;

    //FIXME: make it qpointer
    PersonsModel *model;
};

/******************************** PersonCache *****************************************************/

PersonCache *PersonCache::instance()
{
    return s_globalPersonCache;
}

PersonCache::PersonCache()
  : QObject(0),
    d_ptr(new PersonCachePrivate(this))
{}

PersonCache::~PersonCache()
{
    kDebug();

    delete d_ptr;
}

void PersonCache::startQuery()
{
    Q_D(PersonCache);
    kDebug();

    QString nco_query = QString::fromUtf8("select distinct ?uri ?nao_prefLabel ?pimo_groundingOccurance ?nco_hasIMAccount"
                      "?nco_imNickname ?telepathy_statusType ?nco_imID ?nco_imAccountType ?nco_hasEmailAddress"
                      "?nao_prefSymbol ?telepathy_accountIdentifier ?nco_imStatus ?pimo_prefLabel ?pimo_prefSymbol"

                      "WHERE { ?uri a nco:Contact ."

                      "?uri                       nco:hasIMAccount            ?nco_hasIMAccount ."
                      "?nco_hasIMAccount          nco:imNickname              ?nco_imNickname ."
                      "?nco_hasIMAccount          telepathy:statusType        ?telepathy_statusType ."
                      "?nco_hasIMAccount          nco:imStatus                ?nco_imStatus ."
                      "?nco_hasIMAccount          nco:imID                    ?nco_imID ."
                      "?nco_hasIMAccount          nco:imAccountType           ?nco_imAccountType ."
                      "?nco_hasIMAccount          nco:isAccessedBy            ?nco_isAccessedBy ."
                      "?nco_isAccessedBy          telepathy:accountIdentifier ?telepathy_accountIdentifier ."

                      "OPTIONAL { ?pimo_groundingOccurance  pimo:groundingOccurrence    ?uri . }"
                      "OPTIONAL { ?pimo_groundingOccurance  nao:prefLabel      ?pimo_prefLabel . }"
                      "OPTIONAL { ?pimo_groundingOccurance  nao:prefSymbol     ?pimo_prefSymbol . }"

                      "OPTIONAL { ?uri            nao:prefLabel        ?nao_prefLabel . }"
                      "OPTIONAL { ?uri            nao:prefSymbol       ?nao_prefSymbol . }"
                      "OPTIONAL { ?uri            nco:hasEmailAddress  ?nco_hasEmailAddress . }"

    "}");

    QList<QUrl> list;
    list << Soprano::Vocabulary::NAO::prefLabel()
    << Soprano::Vocabulary::NAO::prefSymbol()
    << Nepomuk::Vocabulary::NCO::imNickname()
    << Nepomuk::Vocabulary::NCO::imAccountType()
    << Nepomuk::Vocabulary::NCO::imID()
    //                      << Nepomuk::Vocabulary::Telepathy::statusType()
    //                      << Nepomuk::Vocabulary::Telepathy::accountIdentifier()
    << QUrl(QLatin1String("http://nepomuk.kde.org/ontologies/2009/06/20/telepathy#statusType"))
    << QUrl(QLatin1String("http://nepomuk.kde.org/ontologies/2009/06/20/telepathy#accountIdentifier"))
    << Nepomuk::Vocabulary::NCO::imStatus()
    << Nepomuk::Vocabulary::NCO::hasEmailAddress();

    Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery(nco_query,
                                                                                Soprano::Query::QueryLanguageSparql);

    QList<PersonsModelContactItem*> nonpersonContacts;

    while(it.next()) {
        QUrl currentUri = it[QLatin1String("uri")].uri();
        QUrl pimoPersonUri = it[QLatin1String("pimo_groundingOccurance")].uri();

        QString display = it[QLatin1String("nao_prefLabel")].toString();
        PersonsModelContactItem* contactNode = new PersonsModelContactItem(currentUri, display);

        Q_FOREACH(const QUrl &keyUri, list) {
            QString keyString = keyUri.toString();
            //convert every key to correspond to the nepomuk bindings
            //FIXME: get this method out of the loop, it repeats too many times for nothing
            keyString = keyString.right(keyString.length() - keyString.lastIndexOf(QLatin1Char('/')) - 1).replace(QLatin1Char('#'), QLatin1Char('_'));

            contactNode->addData(keyUri, it[keyString].toString());
        }

        QHash< QUrl, PersonsModelItem* >::const_iterator pos = d->persons.constFind(pimoPersonUri);
        if (!pimoPersonUri.isEmpty()) {
            if (pos == d->persons.constEnd())
                pos = d->persons.insert(pimoPersonUri, new PersonsModelItem(pimoPersonUri));
            pos.value()->appendRow(contactNode);
        } else {
            kDebug() << "Not a person" << currentUri << pimoPersonUri;
            nonpersonContacts += contactNode;
        }
    }

    // FIXME: Connect up signals/slots so that when the nepomuk context signals something has
    //        happened we relay it to the model

    emit contactsFetched(d->persons.values(), nonpersonContacts);
}

void PersonCache::onNewPersonCreated(Nepomuk::Resource res, QList<QUrl> types)
{
    Q_D(PersonCache);

    bool newPerson = false;
    PersonsModelItem *person = d->persons.value(res.resourceUri());
    if (!person) {
        person = new PersonsModelItem(res.resourceUri());
        newPerson = true;
    }

    kDebug() << "New person created in Nepomuk:" << newPerson;

//     Q_FOREACH (const QUrl &keyUri, types) {
//         if (res.hasProperty(keyUri)) {
//             person->addData(keyUri, res.property(keyUri).variant());
//         }
//     }

    if (newPerson) {
        d->persons.insert(res.resourceUri(), person);
    }

    //TODO: Shouldn't we add the contacts now?
    emit personAddedToCache(person);
}

void PersonCache::onPersonRemoved()
{
    //FIXME: implement me
    //NOTE: We need to know what person was removed
}

void PersonCache::onPersonPropertyChanged(Nepomuk::Resource res, Nepomuk::Types::Property property, QVariant value)
{
    //FIXME: implement me
}

#include "person-cache.moc"
<commit_msg>Not being used...<commit_after>/*
 * This file is part of kpeople
 *
 * Copyright (C) 2010-2011 Collabora Ltd. <info@collabora.co.uk>
 *   @author George Goldberg <george.goldberg@collabora.co.uk>
 *   @author Martin Klapetek <martin.klapetek@gmail.com>
 *
 * Copyright (C) 2012  Aleix Pol Gonzalez <aleixpol@blue-systems.com>
 *
 * 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
 */

#include "person-cache.h"

#include <KDebug>
#include <KGlobal>
#include <KUrl>

#include <QtCore/QHash>

#include <Soprano/Query/QueryLanguage>
#include <Soprano/QueryResultIterator>
#include <Soprano/Model>

#include <Nepomuk/ResourceManager>
#include <Nepomuk/Variant>

#include <Nepomuk/Vocabulary/PIMO>
#include <Nepomuk/Vocabulary/NCO>
#include <Soprano/Vocabulary/NAO>

#include "persons-model.h"
#include "persons-model-item.h"
#include "persons-model-contact-item.h"

K_GLOBAL_STATIC(PersonCache, s_globalPersonCache)

/******************************** PersonCache::Private ********************************************/

class PersonCachePrivate {

protected:
    Q_DECLARE_PUBLIC(PersonCache);
    PersonCache * const q_ptr;

public:
    explicit PersonCachePrivate(PersonCache *q)
    : q_ptr(q)
    { }

    virtual ~PersonCachePrivate()
    { }

    QHash<QUrl, PersonsModelItem*> persons;
    QList<QUrl> allRequestedKeys;
};

/******************************** PersonCache *****************************************************/

PersonCache *PersonCache::instance()
{
    return s_globalPersonCache;
}

PersonCache::PersonCache()
  : QObject(0),
    d_ptr(new PersonCachePrivate(this))
{}

PersonCache::~PersonCache()
{
    kDebug();

    delete d_ptr;
}

void PersonCache::startQuery()
{
    Q_D(PersonCache);
    kDebug();

    QString nco_query = QString::fromUtf8("select distinct ?uri ?nao_prefLabel ?pimo_groundingOccurance ?nco_hasIMAccount"
                      "?nco_imNickname ?telepathy_statusType ?nco_imID ?nco_imAccountType ?nco_hasEmailAddress"
                      "?nao_prefSymbol ?telepathy_accountIdentifier ?nco_imStatus ?pimo_prefLabel ?pimo_prefSymbol"

                      "WHERE { ?uri a nco:Contact ."

                      "?uri                       nco:hasIMAccount            ?nco_hasIMAccount ."
                      "?nco_hasIMAccount          nco:imNickname              ?nco_imNickname ."
                      "?nco_hasIMAccount          telepathy:statusType        ?telepathy_statusType ."
                      "?nco_hasIMAccount          nco:imStatus                ?nco_imStatus ."
                      "?nco_hasIMAccount          nco:imID                    ?nco_imID ."
                      "?nco_hasIMAccount          nco:imAccountType           ?nco_imAccountType ."
                      "?nco_hasIMAccount          nco:isAccessedBy            ?nco_isAccessedBy ."
                      "?nco_isAccessedBy          telepathy:accountIdentifier ?telepathy_accountIdentifier ."

                      "OPTIONAL { ?pimo_groundingOccurance  pimo:groundingOccurrence    ?uri . }"
                      "OPTIONAL { ?pimo_groundingOccurance  nao:prefLabel      ?pimo_prefLabel . }"
                      "OPTIONAL { ?pimo_groundingOccurance  nao:prefSymbol     ?pimo_prefSymbol . }"

                      "OPTIONAL { ?uri            nao:prefLabel        ?nao_prefLabel . }"
                      "OPTIONAL { ?uri            nao:prefSymbol       ?nao_prefSymbol . }"
                      "OPTIONAL { ?uri            nco:hasEmailAddress  ?nco_hasEmailAddress . }"

    "}");

    QList<QUrl> list;
    list << Soprano::Vocabulary::NAO::prefLabel()
    << Soprano::Vocabulary::NAO::prefSymbol()
    << Nepomuk::Vocabulary::NCO::imNickname()
    << Nepomuk::Vocabulary::NCO::imAccountType()
    << Nepomuk::Vocabulary::NCO::imID()
    //                      << Nepomuk::Vocabulary::Telepathy::statusType()
    //                      << Nepomuk::Vocabulary::Telepathy::accountIdentifier()
    << QUrl(QLatin1String("http://nepomuk.kde.org/ontologies/2009/06/20/telepathy#statusType"))
    << QUrl(QLatin1String("http://nepomuk.kde.org/ontologies/2009/06/20/telepathy#accountIdentifier"))
    << Nepomuk::Vocabulary::NCO::imStatus()
    << Nepomuk::Vocabulary::NCO::hasEmailAddress();

    Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery(nco_query,
                                                                                Soprano::Query::QueryLanguageSparql);

    QList<PersonsModelContactItem*> nonpersonContacts;

    while(it.next()) {
        QUrl currentUri = it[QLatin1String("uri")].uri();
        QUrl pimoPersonUri = it[QLatin1String("pimo_groundingOccurance")].uri();

        QString display = it[QLatin1String("nao_prefLabel")].toString();
        PersonsModelContactItem* contactNode = new PersonsModelContactItem(currentUri, display);

        Q_FOREACH(const QUrl &keyUri, list) {
            QString keyString = keyUri.toString();
            //convert every key to correspond to the nepomuk bindings
            //FIXME: get this method out of the loop, it repeats too many times for nothing
            keyString = keyString.right(keyString.length() - keyString.lastIndexOf(QLatin1Char('/')) - 1).replace(QLatin1Char('#'), QLatin1Char('_'));

            contactNode->addData(keyUri, it[keyString].toString());
        }

        QHash< QUrl, PersonsModelItem* >::const_iterator pos = d->persons.constFind(pimoPersonUri);
        if (!pimoPersonUri.isEmpty()) {
            if (pos == d->persons.constEnd())
                pos = d->persons.insert(pimoPersonUri, new PersonsModelItem(pimoPersonUri));
            pos.value()->appendRow(contactNode);
        } else {
            kDebug() << "Not a person" << currentUri << pimoPersonUri;
            nonpersonContacts += contactNode;
        }
    }

    // FIXME: Connect up signals/slots so that when the nepomuk context signals something has
    //        happened we relay it to the model

    emit contactsFetched(d->persons.values(), nonpersonContacts);
}

void PersonCache::onNewPersonCreated(Nepomuk::Resource res, QList<QUrl> types)
{
    Q_D(PersonCache);

    bool newPerson = false;
    PersonsModelItem *person = d->persons.value(res.resourceUri());
    if (!person) {
        person = new PersonsModelItem(res.resourceUri());
        newPerson = true;
    }

    kDebug() << "New person created in Nepomuk:" << newPerson;

//     Q_FOREACH (const QUrl &keyUri, types) {
//         if (res.hasProperty(keyUri)) {
//             person->addData(keyUri, res.property(keyUri).variant());
//         }
//     }

    if (newPerson) {
        d->persons.insert(res.resourceUri(), person);
    }

    //TODO: Shouldn't we add the contacts now?
    emit personAddedToCache(person);
}

void PersonCache::onPersonRemoved()
{
    //FIXME: implement me
    //NOTE: We need to know what person was removed
}

void PersonCache::onPersonPropertyChanged(Nepomuk::Resource res, Nepomuk::Types::Property property, QVariant value)
{
    //FIXME: implement me
}

#include "person-cache.moc"
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2017-2018 IncludeOS AS, Oslo, Norway
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <posix/tcp_fd.hpp>
#include <posix/fd_map.hpp>
#include <kernel/os.hpp>
#include <errno.h>
#include <netinet/in.h>
#include <net/interfaces.hpp>

//#define POSIX_STRACE
#ifdef POSIX_STRACE
#define PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define PRINT(fmt, ...) /* fmt */
#endif

using namespace net;

// return the "currently selected" networking stack
static auto& net_stack() {
  return Interfaces::get(0);
}

ssize_t TCP_FD::read(void* data, size_t len)
{
  return recv(data, len, 0);
}
int TCP_FD::write(const void* data, size_t len)
{
  return send(data, len, 0);
}

int TCP_FD::close()
{
  // connection
  if (this->cd) {
    PRINT("TCP: close(%s)\n", cd->to_string().c_str());
    int ret = cd->close();
    cd = nullptr;
    return ret;
  }
  // listener
  if (this->ld) {
    PRINT("TCP: close(%s)\n", ld->to_string().c_str());
    int ret = ld->close();
    delete ld; ld = nullptr;
    return ret;
  }
  return -EBADF;
}

long TCP_FD::connect(const struct sockaddr* address, socklen_t address_len)
{
  if (is_listener()) {
    PRINT("TCP: connect(%s) failed\n", ld->to_string().c_str());
    // already listening on port
    return -EINVAL;
  }
  if (this->cd) {
    PRINT("TCP: connect(%s) failed\n", cd->to_string().c_str());
    // if its straight-up connected, return that
    if (cd->conn->is_connected()) {
      return -EISCONN;
    }
    // if the connection isn't closed, we can just assume its being used already
    if (!cd->conn->is_closed()) {
      return -EALREADY;
    }
  }

  if (address_len != sizeof(sockaddr_in)) {
    return -EINVAL; // checkme?
  }
  auto* inaddr = (sockaddr_in*) address;

  auto addr = ip4::Addr(::ntohl(inaddr->sin_addr.s_addr));
  auto port = ::htons(inaddr->sin_port);

  PRINT("TCP: connect(%s:%u)\n", addr.to_string().c_str(), port);

  auto outgoing = net_stack().tcp().connect({addr, port});

  bool refused = false;
  outgoing->on_connect([&refused](auto conn) {
    refused = (conn == nullptr);
  });
  // O_NONBLOCK is set for the file descriptor for the socket and the connection
  // cannot be immediately established; the connection shall be established asynchronously.
  if (this->is_blocking() == false) {
    return -EINPROGRESS;
  }

  // wait for connection state to change
  while (not (outgoing->is_connected() or
              outgoing->is_closing() or
              outgoing->is_closed() or
              refused))
  {
    OS::block();
  }
  // set connection whether good or bad
  if (outgoing->is_connected()) {
    // out with the old, in with the new
    this->cd = std::make_unique<TCP_FD_Conn>(outgoing);
    cd->set_default_read();
    return 0;
  }
  // failed to connect
  // TODO: try to distinguish the reason for connection failure
  return -ECONNREFUSED;
}

ssize_t TCP_FD::send(const void* data, size_t len, int fmt)
{
  if (!cd) {
    return -EINVAL;
  }
  return cd->send(data, len, fmt);
}
ssize_t TCP_FD::sendto(const void* data, size_t len, int fmt,
                       const struct sockaddr* dest_addr, socklen_t dest_len)
{
  (void) dest_addr;
  (void) dest_len;
  return send(data, len, fmt);
}
ssize_t TCP_FD::recv(void* dest, size_t len, int flags)
{
  if (!cd) {
    return -EINVAL;
  }
  return cd->recv(dest, len, flags);
}

ssize_t TCP_FD::recvfrom(void* dest, size_t len, int flags, struct sockaddr*, socklen_t*)
{
  return recv(dest, len, flags);
}

long TCP_FD::accept(struct sockaddr *__restrict__ addr, socklen_t *__restrict__ addr_len)
{
  if (!ld) {
    return -EINVAL;
  }
  return ld->accept(addr, addr_len);
}
long TCP_FD::listen(int backlog)
{
  if (!ld) {
    return -EINVAL;
  }
  return ld->listen(backlog);
}
long TCP_FD::bind(const struct sockaddr *addr, socklen_t addrlen)
{
  //
  if (cd or ld) {
    return -EINVAL;
  }
  // verify socket address
  if (addrlen != sizeof(sockaddr_in)) {
    return -EINVAL;
  }
  auto* sin = (sockaddr_in*) addr;
  // verify its AF_INET
  if (sin->sin_family != AF_INET) {
    return -EAFNOSUPPORT;
  }
  // use sin_port for bind
  // its network order ... so swap that shit:
  uint16_t port = ::htons(sin->sin_port);
  // ignore IP address (FIXME?)
  /// TODO: verify that the IP is "local"
  try {
    auto& L = net_stack().tcp().listen(port);
    // remove existing listener
    if (ld) {
      int ret = ld->close();
      if (ret < 0) return ret;
      delete ld;
    }
    // create new one
    ld = new TCP_FD_Listen(L);
    return 0;

  } catch (...) {
    return -EADDRINUSE;
  }
}
int TCP_FD::shutdown(int mode)
{
  if (!cd) {
    return -EINVAL;
  }
  return cd->shutdown(mode);
}

/// socket as connection
TCP_FD_Conn::TCP_FD_Conn(net::tcp::Connection_ptr c)
  : conn{std::move(c)},
    buffer{nullptr}, buf_offset{0}
{
  assert(conn != nullptr);
  set_default_read();

  conn->on_disconnect([this](auto self, auto reason) {
    this->recv_disc = true;
    (void) reason;
    //printf("dc: %s - %s\n", reason.to_string().c_str(), self->to_string().c_str());
    // do nothing, avoid close
    // net::tcp::Connection::Disconnect::CLOSING
    if(not self->is_connected())
      self->close();
  });
}
void TCP_FD_Conn::set_default_read()
{
  conn->on_data({this, &TCP_FD_Conn::retrieve_buffer});
}
ssize_t TCP_FD_Conn::send(const void* data, size_t len, int)
{
  if (not conn->is_connected()) {
    return -ENOTCONN;
  }

  bool written = false;
  conn->on_write([&written] (bool) { written = true; }); // temp

  conn->write(data, len);

  // sometimes we can just write and forget
  if (written) return len;
  while (!written) {
    OS::block();
  }

  conn->on_write(nullptr); // temp
  return len;
}

void TCP_FD_Conn::retrieve_buffer()
{
  if(buffer == nullptr and conn->next_size() > 0)
  {
    buffer = conn->read_next();
    buf_offset = 0;
  }
}
ssize_t TCP_FD_Conn::recv(void* dest, size_t len, int)
{
  if(buffer == nullptr)
    retrieve_buffer();

  // BLOCK HERE:
  // If we havent read the data we asked for or if we're not yet closed/want to close
  while (buffer == nullptr and !conn->is_closed() and !recv_disc) {
    OS::block();
  }

  // means block exited by conn closing
  if(buffer == nullptr)
    return 0;

  // make sure to not read past current buffer
  auto count = std::min(buffer->size() - buf_offset, len);
  Expects(count > 0);
  std::memcpy(dest, buffer->data() + buf_offset, count);
  // increase the offset with how much we read
  buf_offset += count;
  Ensures(buf_offset <= buffer->size());

  // null out the buffer if everything is read from it
  if(buf_offset == buffer->size())
    buffer = nullptr;

  return count;
}
int TCP_FD_Conn::close()
{
  conn->close();
  // wait for connection to close completely
  while (!conn->is_closed()) {
    OS::block();
  }
  return 0;
}
int TCP_FD_Conn::shutdown(int mode)
{
  if (conn->is_closed()) {
    return -ENOTCONN;
  }
  switch (mode) {
  case SHUT_RDWR:
    conn->close();
    return 0;
  case SHUT_RD:
    printf("Ignoring shutdown(SHUT_RD)\n");
    return 0;
  case SHUT_WR:
    printf("Ignoring shutdown(SHUT_WR)\n");
    return 0;
  default:
    return -EINVAL;
  }
}

/// socket as listener

long TCP_FD_Listen::listen(int backlog)
{
  listener.on_connect(
  [this, backlog] (net::tcp::Connection_ptr conn)
  {
    if(UNLIKELY(not conn))
      return;

    // remove oldest if full
    if ((int) this->connq.size() >= backlog)
        this->connq.pop_back();
    // new connection
    this->connq.push_front(std::make_unique<TCP_FD_Conn>(conn));
    /// if someone is blocking they should be leaving right about now
  });
  return 0;
}
long TCP_FD_Listen::accept(struct sockaddr *__restrict__ addr, socklen_t *__restrict__ addr_len)
{
  // block until connection appears
  while (connq.empty()) {
    OS::block();
  }
  // retrieve connection from queue
  auto sock = std::move(connq.back());
  connq.pop_back();

  assert(sock != nullptr);
  // create connected TCP socket
  auto& fd = FD_map::_open<TCP_FD>();
  fd.cd = std::move(sock);
  // set address and length
  if(addr != nullptr and addr_len != nullptr)
  {
    auto& conn = fd.cd->conn;
    auto* sin = (sockaddr_in*) addr;
    sin->sin_family      = AF_INET;
    sin->sin_port        = conn->remote().port();
    sin->sin_addr.s_addr = conn->remote().address().v4().whole;
    *addr_len = sizeof(sockaddr_in);
  }
  // return socket
  return fd.get_id();
}
int TCP_FD_Listen::close()
{
  listener.close();
  return 0;
}
<commit_msg>posix: removed os block if not closed<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2017-2018 IncludeOS AS, Oslo, Norway
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <posix/tcp_fd.hpp>
#include <posix/fd_map.hpp>
#include <kernel/os.hpp>
#include <errno.h>
#include <netinet/in.h>
#include <net/interfaces.hpp>

//#define POSIX_STRACE
#ifdef POSIX_STRACE
#define PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define PRINT(fmt, ...) /* fmt */
#endif

using namespace net;

// return the "currently selected" networking stack
static auto& net_stack() {
  return Interfaces::get(0);
}

ssize_t TCP_FD::read(void* data, size_t len)
{
  return recv(data, len, 0);
}
int TCP_FD::write(const void* data, size_t len)
{
  return send(data, len, 0);
}

int TCP_FD::close()
{
  // connection
  if (this->cd) {
    PRINT("TCP: close(%s)\n", cd->to_string().c_str());
    int ret = cd->close();
    cd = nullptr;
    return ret;
  }
  // listener
  if (this->ld) {
    PRINT("TCP: close(%s)\n", ld->to_string().c_str());
    int ret = ld->close();
    delete ld; ld = nullptr;
    return ret;
  }
  return -EBADF;
}

long TCP_FD::connect(const struct sockaddr* address, socklen_t address_len)
{
  if (is_listener()) {
    PRINT("TCP: connect(%s) failed\n", ld->to_string().c_str());
    // already listening on port
    return -EINVAL;
  }
  if (this->cd) {
    PRINT("TCP: connect(%s) failed\n", cd->to_string().c_str());
    // if its straight-up connected, return that
    if (cd->conn->is_connected()) {
      return -EISCONN;
    }
    // if the connection isn't closed, we can just assume its being used already
    if (!cd->conn->is_closed()) {
      return -EALREADY;
    }
  }

  if (address_len != sizeof(sockaddr_in)) {
    return -EINVAL; // checkme?
  }
  auto* inaddr = (sockaddr_in*) address;

  auto addr = ip4::Addr(::ntohl(inaddr->sin_addr.s_addr));
  auto port = ::htons(inaddr->sin_port);

  PRINT("TCP: connect(%s:%u)\n", addr.to_string().c_str(), port);

  auto outgoing = net_stack().tcp().connect({addr, port});

  bool refused = false;
  outgoing->on_connect([&refused](auto conn) {
    refused = (conn == nullptr);
  });
  // O_NONBLOCK is set for the file descriptor for the socket and the connection
  // cannot be immediately established; the connection shall be established asynchronously.
  if (this->is_blocking() == false) {
    return -EINPROGRESS;
  }

  // wait for connection state to change
  while (not (outgoing->is_connected() or
              outgoing->is_closing() or
              outgoing->is_closed() or
              refused))
  {
    OS::block();
  }
  // set connection whether good or bad
  if (outgoing->is_connected()) {
    // out with the old, in with the new
    this->cd = std::make_unique<TCP_FD_Conn>(outgoing);
    cd->set_default_read();
    return 0;
  }
  // failed to connect
  // TODO: try to distinguish the reason for connection failure
  return -ECONNREFUSED;
}

ssize_t TCP_FD::send(const void* data, size_t len, int fmt)
{
  if (!cd) {
    return -EINVAL;
  }
  return cd->send(data, len, fmt);
}
ssize_t TCP_FD::sendto(const void* data, size_t len, int fmt,
                       const struct sockaddr* dest_addr, socklen_t dest_len)
{
  (void) dest_addr;
  (void) dest_len;
  return send(data, len, fmt);
}
ssize_t TCP_FD::recv(void* dest, size_t len, int flags)
{
  if (!cd) {
    return -EINVAL;
  }
  return cd->recv(dest, len, flags);
}

ssize_t TCP_FD::recvfrom(void* dest, size_t len, int flags, struct sockaddr*, socklen_t*)
{
  return recv(dest, len, flags);
}

long TCP_FD::accept(struct sockaddr *__restrict__ addr, socklen_t *__restrict__ addr_len)
{
  if (!ld) {
    return -EINVAL;
  }
  return ld->accept(addr, addr_len);
}
long TCP_FD::listen(int backlog)
{
  if (!ld) {
    return -EINVAL;
  }
  return ld->listen(backlog);
}
long TCP_FD::bind(const struct sockaddr *addr, socklen_t addrlen)
{
  //
  if (cd or ld) {
    return -EINVAL;
  }
  // verify socket address
  if (addrlen != sizeof(sockaddr_in)) {
    return -EINVAL;
  }
  auto* sin = (sockaddr_in*) addr;
  // verify its AF_INET
  if (sin->sin_family != AF_INET) {
    return -EAFNOSUPPORT;
  }
  // use sin_port for bind
  // its network order ... so swap that shit:
  uint16_t port = ::htons(sin->sin_port);
  // ignore IP address (FIXME?)
  /// TODO: verify that the IP is "local"
  try {
    auto& L = net_stack().tcp().listen(port);
    // remove existing listener
    if (ld) {
      int ret = ld->close();
      if (ret < 0) return ret;
      delete ld;
    }
    // create new one
    ld = new TCP_FD_Listen(L);
    return 0;

  } catch (...) {
    return -EADDRINUSE;
  }
}
int TCP_FD::shutdown(int mode)
{
  if (!cd) {
    return -EINVAL;
  }
  return cd->shutdown(mode);
}

/// socket as connection
TCP_FD_Conn::TCP_FD_Conn(net::tcp::Connection_ptr c)
  : conn{std::move(c)},
    buffer{nullptr}, buf_offset{0}
{
  assert(conn != nullptr);
  set_default_read();

  conn->on_disconnect([this](auto self, auto reason) {
    this->recv_disc = true;
    (void) reason;
    //printf("dc: %s - %s\n", reason.to_string().c_str(), self->to_string().c_str());
    // do nothing, avoid close
    // net::tcp::Connection::Disconnect::CLOSING
    if(not self->is_connected())
      self->close();
  });
}
void TCP_FD_Conn::set_default_read()
{
  conn->on_data({this, &TCP_FD_Conn::retrieve_buffer});
}
ssize_t TCP_FD_Conn::send(const void* data, size_t len, int)
{
  if (not conn->is_connected()) {
    return -ENOTCONN;
  }

  bool written = false;
  conn->on_write([&written] (bool) { written = true; }); // temp

  conn->write(data, len);

  // sometimes we can just write and forget
  if (written) return len;
  while (!written) {
    OS::block();
  }

  conn->on_write(nullptr); // temp
  return len;
}

void TCP_FD_Conn::retrieve_buffer()
{
  if(buffer == nullptr and conn->next_size() > 0)
  {
    buffer = conn->read_next();
    buf_offset = 0;
  }
}
ssize_t TCP_FD_Conn::recv(void* dest, size_t len, int)
{
  if(buffer == nullptr)
    retrieve_buffer();

  // BLOCK HERE:
  // If we havent read the data we asked for or if we're not yet closed/want to close
  while (buffer == nullptr and !conn->is_closed() and !recv_disc) {
    OS::block();
  }

  // means block exited by conn closing
  if(buffer == nullptr)
    return 0;

  // make sure to not read past current buffer
  auto count = std::min(buffer->size() - buf_offset, len);
  Expects(count > 0);
  std::memcpy(dest, buffer->data() + buf_offset, count);
  // increase the offset with how much we read
  buf_offset += count;
  Ensures(buf_offset <= buffer->size());

  // null out the buffer if everything is read from it
  if(buf_offset == buffer->size())
    buffer = nullptr;

  return count;
}
int TCP_FD_Conn::close()
{
  conn->close();
  // wait for connection to close completely
  return 0;
}
int TCP_FD_Conn::shutdown(int mode)
{
  if (conn->is_closed()) {
    return -ENOTCONN;
  }
  switch (mode) {
  case SHUT_RDWR:
    conn->close();
    return 0;
  case SHUT_RD:
    printf("Ignoring shutdown(SHUT_RD)\n");
    return 0;
  case SHUT_WR:
    printf("Ignoring shutdown(SHUT_WR)\n");
    return 0;
  default:
    return -EINVAL;
  }
}

/// socket as listener

long TCP_FD_Listen::listen(int backlog)
{
  listener.on_connect(
  [this, backlog] (net::tcp::Connection_ptr conn)
  {
    if(UNLIKELY(not conn))
      return;

    // remove oldest if full
    if ((int) this->connq.size() >= backlog)
        this->connq.pop_back();
    // new connection
    this->connq.push_front(std::make_unique<TCP_FD_Conn>(conn));
    /// if someone is blocking they should be leaving right about now
  });
  return 0;
}
long TCP_FD_Listen::accept(struct sockaddr *__restrict__ addr, socklen_t *__restrict__ addr_len)
{
  // block until connection appears
  while (connq.empty()) {
    OS::block();
  }
  // retrieve connection from queue
  auto sock = std::move(connq.back());
  connq.pop_back();

  assert(sock != nullptr);
  // create connected TCP socket
  auto& fd = FD_map::_open<TCP_FD>();
  fd.cd = std::move(sock);
  // set address and length
  if(addr != nullptr and addr_len != nullptr)
  {
    auto& conn = fd.cd->conn;
    auto* sin = (sockaddr_in*) addr;
    sin->sin_family      = AF_INET;
    sin->sin_port        = conn->remote().port();
    sin->sin_addr.s_addr = conn->remote().address().v4().whole;
    *addr_len = sizeof(sockaddr_in);
  }
  // return socket
  return fd.get_id();
}
int TCP_FD_Listen::close()
{
  listener.close();
  return 0;
}
<|endoftext|>