<commit_before>#pragma once
#include "dllist.cpp"

template <typename T>
class DoubleLinkedChain : public DoubleLinkedList<T>
{
protected:
    void copy(const DoubleLinkedChain<T>& other)
    {
        if (!other.front || !other.back)
            return;

        DoubleListElement<T> *pFront = other.front, *pn = pFront->prev;
        DoubleLinkedList<T> lFront;

        while (pFront && pFront->prev == pn)
        {
            lFront.insertEnd(pFront->data);
            pn = pFront;
            pFront = pFront->next;
        }

        if (pFront)
        {
            DoubleListElement<T> *pBack = other.back;
            pn = pBack->next;
            DoubleLinkedList<T> lBack;

            while (pBack && pBack->next == pn)
            {
                lBack.insertBegin(pBack->data);
                pn = pBack;
                pBack = pBack->prev;
            }

            lFront.back->next = pFront;
            lBack.front->prev = pBack;
            this->front = lFront.front;
            this->back = lBack.back;
            lBack.back = lBack.front = NULL;
        }
        else
        {
            this->front = lFront.front;
            this->back = lFront.back;
        }

        lFront.back = lFront.front = NULL;
    }

public:
    void clear()
    {
        if (!this->front || !this->back)
            return;

        DoubleListElement<T> *pFront = this->front, *prev = pFront->prev;

        while (pFront && pFront->prev == prev)
        {
            prev = pFront;
            pFront = pFront->next;
        }

        prev->next = NULL;

        DoubleListElement<T> *pBack = this->back, *next = pBack->next;

        while (pBack && pBack->next == next)
        {
            next = pBack;
            pBack = pBack->prev;
        }

        next->prev = NULL;

        DoubleLinkedList<T> lFront, lBack;
        lFront.front = this->front;
        lFront.back = prev;

        if (this->front != next && prev != this->back)
        {
            lBack.front = next;
            lBack.back = this->back;
        }

        this->back = this->front = NULL;
    }

    DoubleLinkedChain()
    {
        this->front = NULL;
        this->back = NULL;
    }

    DoubleLinkedChain(const DoubleLinkedChain& other)
    {
        copy(other);
    }

    DoubleLinkedChain& operator=(const DoubleLinkedChain& other)
    {
        if (&other != this)
        {
            clear();
            copy(other);
        }

        return *this;
    }

    ~DoubleLinkedChain()
    {
        clear();
    }

    DoubleListElement<T>* getFrontPtr() { return this->front; }
    const DoubleListElement<T>* getFrontPtr() const { return this->front; }

    DoubleListElement<T>* getBackPtr() { return this->back; }
    const DoubleListElement<T>* getBackPtr() const { return this->back; }

    bool adoptList(DoubleLinkedList<T>& l)
    {
        if (!l.front || !l.back)
            return false;

        clear();
        this->front = l.front;
        this->back = l.back;
        l.front = NULL;
        l.back = NULL;
        return true;
    }

    bool attachAtBegin(DoubleLinkedList<T>& l, DoubleLinkedListIterator<T>& it)
    {
        if (it)
        {
            if (this->front)
            {
                this->front->prev = it.ptr;

                if (it.ptr == l.back)
                    it.ptr->next = this->front;

                while (this->front && this->front->prev)
                    this->front = this->front->prev;
            }
            else
            {
                this->front = l.front;
                this->back = l.back;
            }

            l.front = NULL;
            l.back = NULL;
            return true;
        }
        else
            return false;
    }

    bool attachAtEnd(DoubleLinkedList<T>& l, DoubleLinkedListIterator<T>& it)
    {
        if (it)
        {
            if (this->back)
            {
                this->back->next = it.ptr;

                if (it.ptr == l.front)
                    it.ptr->prev = this->back;

                while (this->back && this->back->next)
                    this->back = this->back->next;
            }
            else
            {
                this->front = l.front;
                this->back = l.back;
            }

            l.front = NULL;
            l.back = NULL;
            return true;
        }
        else
            return false;
    }

    bool attachListAtFront(DoubleLinkedList<T>& l, DoubleLinkedListIterator<T>& it)
    {
        if (it && l.front && !l.front->prev)
        {
            l.front->prev = it.ptr;

            if (it.ptr == this->back)
            {
                this->back->next = l.front;

                while (this->back && this->back->next)
                    this->back = this->back->next;
            }

            return true;
        }
        else
            return false;
    }

    bool attachListAtBack(DoubleLinkedList<T>& l,
            DoubleLinkedListIterator<T>& it)
    {
        if (it && l.back && !l.back->next)
        {
            l.back->next = it.ptr;

            if (it.ptr == this->front)
            {
                this->front->back = l.back;

                while (this->front && this->front->prev)
                    this->front = this->front->prev;
            }

            return true;
        }
        else
            return false;
    }

    bool join_at(DoubleLinkedList<T>& L1, DoubleLinkedList<T>& L2,
            DoubleLinkedListIterator<T>& M1, DoubleLinkedListIterator<T>& M2)
    {
        return adoptList(L1) && attachListAtFront(L2, M1) &&
                                attachAtEnd(L2, M2);
    }

    bool join(DoubleLinkedList<T>& L1, DoubleLinkedList<T>& L2)
    {
        DoubleLinkedListIterator<T> itL1 = L1.begin(), itL2 = L2.end(), M1, M2;

        while (itL1 && itL2)
        {
            if (*itL1 == *itL2 && (!M1 || *itL1 > *M1))
            {
                M1 = itL1;
                M2 = itL2;
            }

            itL1++;
            itL2--;
        }

        itL1 = L1.end();
        itL2 = L2.begin();

        while (itL1 && itL2)
        {
            if (*itL1 == *itL2 && (!M1 || *itL1 > *M1))
            {
                M1 = itL1;
                M2 = itL2;
            }

            itL1--;
            itL2++;
        }

        return join_at(L1, L2, M1, M2);
    }

    bool isJoined() const
    {
        if (!this->front || !this->back)
            return false;

        DoubleListElement<T> *pFront = this->front, *pn = pFront->prev;

        while (pFront && pFront->prev == pn)
        {
            pn = pFront;
            pFront = pFront->next;
        }

        DoubleListElement<T> *pBack = this->back;
        pn = pBack->next;

        while (pBack && pBack->next == pn)
        {
            pn = pBack;
            pBack = pBack->prev;
        }

        return pFront && pBack;
    }

    T sum() const
    {
        T S = T();

        if (!this->front || !this->back)
            return S;

        DoubleListElement<T> *pFront = this->front, *pn = pFront->prev;

        while (pFront && pFront->prev == pn)
        {
            S += pFront->data;
            pn = pFront;
            pFront = pFront->next;
        }

        if (pFront)
        {
            DoubleListElement<T> *pBack = this->back;
            pn = pBack->next;

            while (pBack && pBack->next == pn)
            {
                S += pBack->data;
                pn = pBack;
                pBack = pBack->prev;
            }
        }

        return S;
    }
};
<commit_msg>fixed formatting issue<commit_after>#pragma once
#include "dllist.cpp"

template <typename T>
class DoubleLinkedChain : public DoubleLinkedList<T>
{
protected:
    void copy(const DoubleLinkedChain<T>& other)
    {
        if (!other.front || !other.back)
            return;

        DoubleListElement<T> *pFront = other.front, *pn = pFront->prev;
        DoubleLinkedList<T> lFront;

        while (pFront && pFront->prev == pn)
        {
            lFront.insertEnd(pFront->data);
            pn = pFront;
            pFront = pFront->next;
        }

        if (pFront)
        {
            DoubleListElement<T> *pBack = other.back;
            pn = pBack->next;
            DoubleLinkedList<T> lBack;

            while (pBack && pBack->next == pn)
            {
                lBack.insertBegin(pBack->data);
                pn = pBack;
                pBack = pBack->prev;
            }

            lFront.back->next = pFront;
            lBack.front->prev = pBack;
            this->front = lFront.front;
            this->back = lBack.back;
            lBack.back = lBack.front = NULL;
        }
        else
        {
            this->front = lFront.front;
            this->back = lFront.back;
        }

        lFront.back = lFront.front = NULL;
    }

public:
    void clear()
    {
        if (!this->front || !this->back)
            return;

        DoubleListElement<T> *pFront = this->front, *prev = pFront->prev;

        while (pFront && pFront->prev == prev)
        {
            prev = pFront;
            pFront = pFront->next;
        }

        prev->next = NULL;

        DoubleListElement<T> *pBack = this->back, *next = pBack->next;

        while (pBack && pBack->next == next)
        {
            next = pBack;
            pBack = pBack->prev;
        }

        next->prev = NULL;

        DoubleLinkedList<T> lFront, lBack;
        lFront.front = this->front;
        lFront.back = prev;

        if (this->front != next && prev != this->back)
        {
            lBack.front = next;
            lBack.back = this->back;
        }

        this->back = this->front = NULL;
    }

    DoubleLinkedChain()
    {
        this->front = NULL;
        this->back = NULL;
    }

    DoubleLinkedChain(const DoubleLinkedChain& other)
    {
        copy(other);
    }

    DoubleLinkedChain& operator=(const DoubleLinkedChain& other)
    {
        if (&other != this)
        {
            clear();
            copy(other);
        }

        return *this;
    }

    ~DoubleLinkedChain()
    {
        clear();
    }

    DoubleListElement<T>* getFrontPtr() { return this->front; }
    const DoubleListElement<T>* getFrontPtr() const { return this->front; }

    DoubleListElement<T>* getBackPtr() { return this->back; }
    const DoubleListElement<T>* getBackPtr() const { return this->back; }

    bool adoptList(DoubleLinkedList<T>& l)
    {
        if (!l.front || !l.back)
            return false;

        clear();
        this->front = l.front;
        this->back = l.back;
        l.front = NULL;
        l.back = NULL;
        return true;
    }

    bool attachAtBegin(DoubleLinkedList<T>& l, DoubleLinkedListIterator<T>& it)
    {
        if (it)
        {
            if (this->front)
            {
                this->front->prev = it.ptr;

                if (it.ptr == l.back)
                    it.ptr->next = this->front;

                while (this->front && this->front->prev)
                    this->front = this->front->prev;
            }
            else
            {
                this->front = l.front;
                this->back = l.back;
            }

            l.front = NULL;
            l.back = NULL;
            return true;
        }
        else
            return false;
    }

    bool attachAtEnd(DoubleLinkedList<T>& l, DoubleLinkedListIterator<T>& it)
    {
        if (it)
        {
            if (this->back)
            {
                this->back->next = it.ptr;

                if (it.ptr == l.front)
                    it.ptr->prev = this->back;

                while (this->back && this->back->next)
                    this->back = this->back->next;
            }
            else
            {
                this->front = l.front;
                this->back = l.back;
            }

            l.front = NULL;
            l.back = NULL;
            return true;
        }
        else
            return false;
    }

    bool attachListAtFront(DoubleLinkedList<T>& l,
                           DoubleLinkedListIterator<T>& it)
    {
        if (it && l.front && !l.front->prev)
        {
            l.front->prev = it.ptr;

            if (it.ptr == this->back)
            {
                this->back->next = l.front;

                while (this->back && this->back->next)
                    this->back = this->back->next;
            }

            return true;
        }
        else
            return false;
    }

    bool attachListAtBack(DoubleLinkedList<T>& l,
            DoubleLinkedListIterator<T>& it)
    {
        if (it && l.back && !l.back->next)
        {
            l.back->next = it.ptr;

            if (it.ptr == this->front)
            {
                this->front->back = l.back;

                while (this->front && this->front->prev)
                    this->front = this->front->prev;
            }

            return true;
        }
        else
            return false;
    }

    bool join_at(DoubleLinkedList<T>& L1, DoubleLinkedList<T>& L2,
            DoubleLinkedListIterator<T>& M1, DoubleLinkedListIterator<T>& M2)
    {
        return adoptList(L1) && attachListAtFront(L2, M1) &&
                                attachAtEnd(L2, M2);
    }

    bool join(DoubleLinkedList<T>& L1, DoubleLinkedList<T>& L2)
    {
        DoubleLinkedListIterator<T> itL1 = L1.begin(), itL2 = L2.end(), M1, M2;

        while (itL1 && itL2)
        {
            if (*itL1 == *itL2 && (!M1 || *itL1 > *M1))
            {
                M1 = itL1;
                M2 = itL2;
            }

            itL1++;
            itL2--;
        }

        itL1 = L1.end();
        itL2 = L2.begin();

        while (itL1 && itL2)
        {
            if (*itL1 == *itL2 && (!M1 || *itL1 > *M1))
            {
                M1 = itL1;
                M2 = itL2;
            }

            itL1--;
            itL2++;
        }

        return join_at(L1, L2, M1, M2);
    }

    bool isJoined() const
    {
        if (!this->front || !this->back)
            return false;

        DoubleListElement<T> *pFront = this->front, *pn = pFront->prev;

        while (pFront && pFront->prev == pn)
        {
            pn = pFront;
            pFront = pFront->next;
        }

        DoubleListElement<T> *pBack = this->back;
        pn = pBack->next;

        while (pBack && pBack->next == pn)
        {
            pn = pBack;
            pBack = pBack->prev;
        }

        return pFront && pBack;
    }

    T sum() const
    {
        T S = T();

        if (!this->front || !this->back)
            return S;

        DoubleListElement<T> *pFront = this->front, *pn = pFront->prev;

        while (pFront && pFront->prev == pn)
        {
            S += pFront->data;
            pn = pFront;
            pFront = pFront->next;
        }

        if (pFront)
        {
            DoubleListElement<T> *pBack = this->back;
            pn = pBack->next;

            while (pBack && pBack->next == pn)
            {
                S += pBack->data;
                pn = pBack;
                pBack = pBack->prev;
            }
        }

        return S;
    }
};
<|endoftext|>


<commit_before>/**
 *	\file
 */

#pragma once

#include "future.hpp"
#include <boost/asio.hpp>
#include <curl/curl.h>
#include <cstddef>
#include <exception>
#include <memory>
#include <mutex>
#include <unordered_map>

namespace asiocurl {

	/**
	 *	Services curl easy handles using Boost.ASIO.
	 */
	class io_service {

		private:

			class control {

				private:

					using mutex_type=std::recursive_mutex;
					mutable mutex_type m_;
					bool stop_;

				public:

					control (const control &) = delete;
					control (control &&) = delete;
					control & operator = (const control &) = delete;
					control & operator = (control &&) = delete;

					control ();

					using guard_type=std::unique_lock<mutex_type>;
					guard_type lock () const noexcept;
					explicit operator bool () const noexcept;
					void stop () noexcept;

			};

			class easy_state {

				public:

					CURL * easy;
					std::exception_ptr ex;
					promise<CURLMsg> promise;

					easy_state () = delete;
					easy_state (const easy_state &) = delete;
					easy_state (easy_state &&) = default;
					easy_state & operator = (const easy_state &) = delete;
					easy_state & operator = (easy_state &&) = delete;

					explicit easy_state (CURL *);

					void set_exception () noexcept;
					void set_exception (std::exception_ptr) noexcept;

			};

			class socket_state {

				public:

					int what;
					bool read;
					bool write;
					bool closed;
					boost::asio::ip::tcp::socket socket;

					socket_state () = delete;
					socket_state (const socket_state &) = delete;
					socket_state (socket_state &&) = default;
					socket_state & operator = (const socket_state &) = delete;
					socket_state & operator = (socket_state &&) = delete;

					socket_state (const boost::asio::ip::tcp::socket::protocol_type &, boost::asio::io_service &);

			};

			boost::asio::io_service & ios_;
			CURLM * handle_;
			using handles_type=std::unordered_map<CURL *,easy_state>;
			handles_type handles_;
			using sockets_type=std::unordered_map<curl_socket_t,socket_state>;
			sockets_type sockets_;
			std::shared_ptr<control> control_;
			boost::asio::deadline_timer timer_;

			static curl_socket_t open (void *, curlsocktype, struct curl_sockaddr *) noexcept;
			static int close (void *, curl_socket_t) noexcept;
			static int socket (CURL *, curl_socket_t, int, void *, void *) noexcept;
			static int timer (CURLM *, long, void *) noexcept;

			void do_action (curl_socket_t, int) noexcept;
			void remove_socket (sockets_type::iterator) noexcept;
			void abort (easy_state &) noexcept;
			void abort (handles_type::iterator) noexcept;
			void complete (CURLMsg) noexcept;
			void read (socket_state &);
			void write (socket_state &);

		public:

			io_service () = delete;
			io_service (const io_service &) = delete;
			io_service (io_service &&) = delete;
			io_service & operator = (const io_service &) = delete;
			io_service & operator = (io_service &&) = delete;

			explicit io_service (boost::asio::io_service & ios);

			~io_service () noexcept;

			/**
			 *	Adds a curl easy handle to be managed by this io_service.
			 *
			 *	The io_service does not assume ownership of the easy handle
			 *	and the easy handle must remain valid until the io_service
			 *	is done with it.
			 *
			 *	\param [in] easy
			 *		The easy handle to add to the io_service.
			 *
			 *	\return
			 *		A handle to the future value of the completed transfer
			 *		represented by the easy handle.
			 */
			future<CURLMsg> add (CURL * easy);

			/**
			 *	Removes a curl easy handle from the io_service.
			 *
			 *	Once this call completes the io_service will no longer
			 *	use the easy handle.
			 *
			 *	Note that the io_service does not reset any options it has
			 *	set on the easy handle.  Accordingly reusing the easy handle
			 *	without calling curl_easy_reset on it leads to undefined behaviour
			 *	unless the new transfer is handled through the same io_service.
			 *
			 *	If \em easy was never added to this io_service, or if the
			 *	transfer has completed, nothing happens.
			 *
			 *	Note that it is not necessary to call this function after
			 *	a transfer completes: In this instance the easy handle is
			 *	automatically disassociated from the io_service.
			 *
			 *	\param [in] easy
			 *		The easy handle to disassociate from the io_service.
			 *
			 *	\return
			 *		\em true if \em easy was disassociated from the
			 *		io_service, \em false if \em easy was not associated
			 *		with the io_service.
			 */
			bool remove (CURL * easy) noexcept;

	};

}
<commit_msg>asiocurl::io_service - Constructor & Destructor Documentation<commit_after>/**
 *	\file
 */

#pragma once

#include "future.hpp"
#include <boost/asio.hpp>
#include <curl/curl.h>
#include <cstddef>
#include <exception>
#include <memory>
#include <mutex>
#include <unordered_map>

namespace asiocurl {

	/**
	 *	Services curl easy handles using Boost.ASIO.
	 */
	class io_service {

		private:

			class control {

				private:

					using mutex_type=std::recursive_mutex;
					mutable mutex_type m_;
					bool stop_;

				public:

					control (const control &) = delete;
					control (control &&) = delete;
					control & operator = (const control &) = delete;
					control & operator = (control &&) = delete;

					control ();

					using guard_type=std::unique_lock<mutex_type>;
					guard_type lock () const noexcept;
					explicit operator bool () const noexcept;
					void stop () noexcept;

			};

			class easy_state {

				public:

					CURL * easy;
					std::exception_ptr ex;
					promise<CURLMsg> promise;

					easy_state () = delete;
					easy_state (const easy_state &) = delete;
					easy_state (easy_state &&) = default;
					easy_state & operator = (const easy_state &) = delete;
					easy_state & operator = (easy_state &&) = delete;

					explicit easy_state (CURL *);

					void set_exception () noexcept;
					void set_exception (std::exception_ptr) noexcept;

			};

			class socket_state {

				public:

					int what;
					bool read;
					bool write;
					bool closed;
					boost::asio::ip::tcp::socket socket;

					socket_state () = delete;
					socket_state (const socket_state &) = delete;
					socket_state (socket_state &&) = default;
					socket_state & operator = (const socket_state &) = delete;
					socket_state & operator = (socket_state &&) = delete;

					socket_state (const boost::asio::ip::tcp::socket::protocol_type &, boost::asio::io_service &);

			};

			boost::asio::io_service & ios_;
			CURLM * handle_;
			using handles_type=std::unordered_map<CURL *,easy_state>;
			handles_type handles_;
			using sockets_type=std::unordered_map<curl_socket_t,socket_state>;
			sockets_type sockets_;
			std::shared_ptr<control> control_;
			boost::asio::deadline_timer timer_;

			static curl_socket_t open (void *, curlsocktype, struct curl_sockaddr *) noexcept;
			static int close (void *, curl_socket_t) noexcept;
			static int socket (CURL *, curl_socket_t, int, void *, void *) noexcept;
			static int timer (CURLM *, long, void *) noexcept;

			void do_action (curl_socket_t, int) noexcept;
			void remove_socket (sockets_type::iterator) noexcept;
			void abort (easy_state &) noexcept;
			void abort (handles_type::iterator) noexcept;
			void complete (CURLMsg) noexcept;
			void read (socket_state &);
			void write (socket_state &);

		public:

			io_service () = delete;
			io_service (const io_service &) = delete;
			io_service (io_service &&) = delete;
			io_service & operator = (const io_service &) = delete;
			io_service & operator = (io_service &&) = delete;

			/**
			 *	Creates a new io_service which uses a certain
			 *	boost::asio::io_service for socket I/O and timeouts.
			 *
			 *	\param [in] ios
			 *		The boost::asio::io_service with which this io_service
			 *		shall be associated.  This reference must remain valid
			 *		for the lifetime of the io_service or the behaviour is
			 *		undefined.
			 */
			explicit io_service (boost::asio::io_service & ios);

			/**
			 *	Shuts the io_service down.
			 *
			 *	Any pending transfers will be immediately aborted.
			 *
			 *	Any pending asynchronous operations will be cancelled.  When
			 *	those pending operations complete they will be no ops (i.e.
			 *	it is not necessary to drain the boost::asio::io_service before
			 *	calling this destructor).
			 */
			~io_service () noexcept;

			/**
			 *	Adds a curl easy handle to be managed by this io_service.
			 *
			 *	The io_service does not assume ownership of the easy handle
			 *	and the easy handle must remain valid until the io_service
			 *	is done with it.
			 *
			 *	\param [in] easy
			 *		The easy handle to add to the io_service.
			 *
			 *	\return
			 *		A handle to the future value of the completed transfer
			 *		represented by the easy handle.
			 */
			future<CURLMsg> add (CURL * easy);

			/**
			 *	Removes a curl easy handle from the io_service.
			 *
			 *	Once this call completes the io_service will no longer
			 *	use the easy handle.
			 *
			 *	Note that the io_service does not reset any options it has
			 *	set on the easy handle.  Accordingly reusing the easy handle
			 *	without calling curl_easy_reset on it leads to undefined behaviour
			 *	unless the new transfer is handled through the same io_service.
			 *
			 *	If \em easy was never added to this io_service, or if the
			 *	transfer has completed, nothing happens.
			 *
			 *	Note that it is not necessary to call this function after
			 *	a transfer completes: In this instance the easy handle is
			 *	automatically disassociated from the io_service.
			 *
			 *	\param [in] easy
			 *		The easy handle to disassociate from the io_service.
			 *
			 *	\return
			 *		\em true if \em easy was disassociated from the
			 *		io_service, \em false if \em easy was not associated
			 *		with the io_service.
			 */
			bool remove (CURL * easy) noexcept;

	};

}
<|endoftext|>


<commit_before>#pragma once
#include <vector>
#include <map>
#include <string>
#include <functional>
#include "function_traits.hpp"
#include "string_utils.hpp"
//#include "tuple_utils.hpp"
#include "token_parser.hpp"
#include "request.hpp"
#include "response.hpp"

namespace cinatra
{
	class HTTPRouter
	{
		typedef std::function<bool(Request&, Response&, token_parser &)> invoker_function;
	public:
		HTTPRouter()
		{}

		template<typename Function>
		typename std::enable_if<!std::is_member_function_pointer<Function>::value>::type route(const std::string& name, const Function& f)
		{
			std::string funcName = getFuncName(name);

			register_nonmenber_impl<Function>(funcName, f); //对函数指针有效.
		}

		std::string getFuncName(std::string name)
		{
			size_t pos = name.find_first_of(':');
			if (pos == std::string::npos)
				return name;

			std::string funcName = name.substr(0, pos - 1);
			std::vector<string> v;
			while (pos != string::npos)
			{
				//获取参数key，/hello/:name/:age
				size_t nextpos = name.find_first_of('/', pos);
				string paramKey = name.substr(pos + 1, nextpos - pos - 1);
				v.push_back(std::move(paramKey));

				pos = name.find_first_of(':', nextpos);
			}
			parser_.add(name, v);
			return funcName;
		}

		template<typename Function, typename Self>
		typename std::enable_if<std::is_member_function_pointer<Function>::value>::type route(const std::string& name, const Function& f, Self* self)
		{
			std::string funcName = getFuncName(name);
			register_member_impl<Function, Function, Self>(funcName, f, self);
		}

		void remove_function(const std::string& name) {
			this->map_invokers.erase(name);
		}

		bool dispatch(Request& req,  Response& resp)
		{
			token_parser parser;
			parser.parse(req, parser_.get_map());

			if (parser.empty())
				return false;

			std::string func_name = parser.get_function_name();
			if (func_name.empty())
			{
				return nullptr;
			}

			bool r = false;
			auto it = map_invokers.equal_range(func_name);

			for (auto itr = it.first; itr != it.second; ++itr)
			{
				try
				{
					auto it = resp.context().find(PARAM_ERROR);
					if (it != resp.context().end())
					{
						resp.context().erase(it);
					}
					r = itr->second(req, resp, parser);
				}
				catch (const std::exception& e)
				{
					LOG_INFO << e.what();
					r = false;
				}

				if (resp.context().find(PARAM_ERROR) == resp.context().end())
					return r;
			}

			if (it.first==it.second)
			{
				//处理非标准的情况.
				size_t pos = func_name.rfind('/');
				while (pos != string::npos&&pos!=0)
				{
					string name = func_name;
					if (pos != 0)
						name = func_name.substr(0, pos);

					string params = func_name.substr(pos);
					parser.parse(params);

					auto it = map_invokers.equal_range(name);
					for (auto itr = it.first; itr != it.second; ++itr)
					{
						try
						{
							auto it = resp.context().find(PARAM_ERROR);
							if (it != resp.context().end())
							{
								resp.context().erase(it);
							}
							r = itr->second(req, resp, parser);
						}
						catch (const std::exception& e)
						{
							LOG_INFO << e.what();
							r = false;
						}

						if (resp.context().find(PARAM_ERROR) == resp.context().end())
							return r;
					}

					pos = func_name.rfind('/', pos - 1);
				}
			}

			return r;
		}

		//如果有参数key就按照key从query里取出相应的参数值.
		//如果没有则直接查找，需要逐步匹配，先匹配最长的，接着匹配次长的，直到查找完所有可能的path.
		invoker_function getFunction(token_parser& parser)
		{
			std::string func_name = parser.get_function_name();
			if (func_name.empty())
			{
				return nullptr;
			}
			auto it = map_invokers.find(func_name);
			if (it != map_invokers.end())
				return it->second;

			//处理非标准的情况.
			size_t pos = func_name.rfind('/');
			while (pos != string::npos)
			{
				string& name = func_name;
				if (pos!=0)
					name = func_name.substr(0, pos);
				auto it = map_invokers.find(name);
				if (it == map_invokers.end())
				{
					pos = func_name.rfind('/', pos - 1);
					if (pos == 0)
						return nullptr;
				}
				else
				{
					string params = func_name.substr(pos);
					parser.parse(params);
					return it->second;
				}
			}

			return nullptr;
		}

	public:
		template<class Signature, typename Function>
		void register_nonmenber_impl(const std::string& name, const Function& f)
		{
			// instantiate and store the invoker by name
			this->map_invokers.emplace(name, std::bind(&invoker<Function, Signature>::template call<std::tuple<>>, f, std::placeholders::_1,
				std::placeholders::_2, std::placeholders::_3,
				std::tuple<>()));
		}

		template<class Signature, typename Function, typename Self>
		void register_member_impl(const std::string& name, const Function& f, Self* self)
		{
			// instantiate and store the invoker by name
			this->map_invokers.emplace(name, std::bind(&invoker<Function, Signature>::template call_member<std::tuple<>, Self>, f, self, std::placeholders::_1,
				std::placeholders::_2, std::placeholders::_3,
				std::tuple<>()));
		}

	private:
		template<typename Function, class Signature = Function, size_t N = function_traits<Signature>::arity>
		struct invoker;

		template<typename Function, class Signature, size_t N>
		struct invoker
		{
			// add an argument to a Fusion cons-list for each parameter type
			template<typename Args>
			static inline bool call(const Function& func, Request& req, Response& res, token_parser & parser, const Args& args)
			{
				if (N != parser.size() + 2)
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				typedef typename function_traits<Signature>::template args<N-1>::type arg_type;
				typename std::decay<arg_type>::type param;
				if (!parser.get<arg_type>(param))
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}
				return HTTPRouter::invoker<Function, Signature, N - 1>::call(func, req, res, parser, std::tuple_cat(std::make_tuple(param), args));
			}

			template<typename Args, typename Self>
			static inline bool call_member(Function func, Self* self, Request& req, Response& res, token_parser & parser, const Args& args)
			{
				if (N != parser.size() + 2)
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				typedef typename function_traits<Signature>::template args<N-1>::type arg_type;
				typename std::decay<arg_type>::type param;
				if (!parser.get<arg_type>(param))
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}
				return HTTPRouter::invoker<Function, Signature, N - 1>::call_member(func, self, req, res, parser, std::tuple_cat(std::make_tuple(param), args));
			}
		};

		template<typename Function, class Signature>
		struct invoker<Function, Signature, 2>
		{
			// the argument list is complete, now call the function
			template<typename Args>
			static inline bool call(const Function& func, Request& req, Response& res, token_parser &parser, const Args& args)
			{
				if (function_traits<Signature>::arity == 2 && !parser.empty())
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				apply(func, req, res, args);
				return true;
			}

			template<typename Args, typename Self>
			static inline bool call_member(const Function& func, Self* self, Request& req, Response& res, token_parser &parser, const Args& args)
			{
				if (function_traits<Signature>::arity == 2 && !parser.empty())
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				apply_member(func, self, req, res, args);
				return true;
			}
		};

		template<int...>
		struct IndexTuple{};

		template<int N, int... Indexes>
		struct MakeIndexes : MakeIndexes<N - 1, N - 1, Indexes...>{};

		template<int... indexes>
		struct MakeIndexes<0, indexes...>
		{
			typedef IndexTuple<indexes...> type;
		};

		template<typename F, int ... Indexes, typename ... Args>
		static void apply_helper(const F& f, Request& req, Response& res, IndexTuple<Indexes...>, const std::tuple<Args...>& tup)
		{
			f(req, res, std::get<Indexes>(tup)...);
		}

		template<typename F, typename ... Args>
		static void apply(const F& f, Request& req, Response& res, const std::tuple<Args...>& tp)
		{
			apply_helper(f, req, res, typename MakeIndexes<sizeof... (Args)>::type(), tp);
		}

		template<typename F, typename Self, int ... Indexes, typename ... Args>
		static void apply_helper_member(const F& f, Self* self, Request& req, Response& res, IndexTuple<Indexes...>, const std::tuple<Args...>& tup)
		{
			(*self.*f)(req, res, std::get<Indexes>(tup)...);
		}

		template<typename F, typename Self, typename ... Args>
		static void apply_member(const F& f, Self* self, Request& req, Response& res, const std::tuple<Args...>& tp)
		{
			apply_helper_member(f, self, req, res, typename MakeIndexes<sizeof... (Args)>::type(), tp);
		}

	private:
		std::multimap<std::string, invoker_function> map_invokers;
		token_parser parser_;
		const static int PARAM_ERROR = -9999;
	};
}
<commit_msg>去掉一些重复代码。<commit_after>#pragma once
#include <vector>
#include <map>
#include <string>
#include <functional>
#include "function_traits.hpp"
#include "string_utils.hpp"
//#include "tuple_utils.hpp"
#include "token_parser.hpp"
#include "request.hpp"
#include "response.hpp"

namespace cinatra
{
	class HTTPRouter
	{
		typedef std::function<bool(Request&, Response&, token_parser &)> invoker_function;
	public:
		HTTPRouter()
		{}

		template<typename Function>
		typename std::enable_if<!std::is_member_function_pointer<Function>::value>::type route(const std::string& name, const Function& f)
		{
			std::string funcName = getFuncName(name);

			register_nonmenber_impl<Function>(funcName, f); //对函数指针有效.
		}

		std::string getFuncName(std::string name)
		{
			size_t pos = name.find_first_of(':');
			if (pos == std::string::npos)
				return name;

			std::string funcName = name.substr(0, pos - 1);
			std::vector<string> v;
			while (pos != string::npos)
			{
				//获取参数key，/hello/:name/:age
				size_t nextpos = name.find_first_of('/', pos);
				string paramKey = name.substr(pos + 1, nextpos - pos - 1);
				v.push_back(std::move(paramKey));

				pos = name.find_first_of(':', nextpos);
			}
			parser_.add(name, v);
			return funcName;
		}

		template<typename Function, typename Self>
		typename std::enable_if<std::is_member_function_pointer<Function>::value>::type route(const std::string& name, const Function& f, Self* self)
		{
			std::string funcName = getFuncName(name);
			register_member_impl<Function, Function, Self>(funcName, f, self);
		}

		void remove_function(const std::string& name) {
			this->map_invokers.erase(name);
		}

		bool dispatch(Request& req,  Response& resp)
		{
			token_parser parser;
			parser.parse(req, parser_.get_map());

			if (parser.empty())
				return false;

			std::string func_name = parser.get_function_name();
			if (func_name.empty())
			{
				return nullptr;
			}

			bool finish = false;
			bool r = handle(req, resp, func_name, parser, finish);
			if (finish)
				return r;

			auto it = map_invokers.equal_range(func_name);
			if (it.first==it.second)
			{
				//处理非标准的情况.
				size_t pos = func_name.rfind('/');
				while (pos != string::npos&&pos!=0)
				{
					string name = func_name;
					if (pos != 0)
						name = func_name.substr(0, pos);

					string params = func_name.substr(pos);
					parser.parse(params);

					bool r = handle(req, resp, name, parser, finish);
					if (finish)
						return r;

					pos = func_name.rfind('/', pos - 1);
				}
			}

			return r;
		}

		bool handle(Request& req, Response& resp, string& name, token_parser& parser, bool& finish)
		{
			bool r = false;
			auto it = map_invokers.equal_range(name);
			for (auto itr = it.first; itr != it.second; ++itr)
			{
				try
				{
					auto it = resp.context().find(PARAM_ERROR);
					if (it != resp.context().end())
					{
						resp.context().erase(it);
					}
					r = itr->second(req, resp, parser);
				}
				catch (const std::exception& e)
				{
					LOG_INFO << e.what();
					r = false;
				}

				if (resp.context().find(PARAM_ERROR) == resp.context().end())
				{
					finish = true;
					break;
				}
			}

			return r;
		}

		//如果有参数key就按照key从query里取出相应的参数值.
		//如果没有则直接查找，需要逐步匹配，先匹配最长的，接着匹配次长的，直到查找完所有可能的path.
		invoker_function getFunction(token_parser& parser)
		{
			std::string func_name = parser.get_function_name();
			if (func_name.empty())
			{
				return nullptr;
			}
			auto it = map_invokers.find(func_name);
			if (it != map_invokers.end())
				return it->second;

			//处理非标准的情况.
			size_t pos = func_name.rfind('/');
			while (pos != string::npos)
			{
				string& name = func_name;
				if (pos!=0)
					name = func_name.substr(0, pos);
				auto it = map_invokers.find(name);
				if (it == map_invokers.end())
				{
					pos = func_name.rfind('/', pos - 1);
					if (pos == 0)
						return nullptr;
				}
				else
				{
					string params = func_name.substr(pos);
					parser.parse(params);
					return it->second;
				}
			}

			return nullptr;
		}

	public:
		template<class Signature, typename Function>
		void register_nonmenber_impl(const std::string& name, const Function& f)
		{
			// instantiate and store the invoker by name
			this->map_invokers.emplace(name, std::bind(&invoker<Function, Signature>::template call<std::tuple<>>, f, std::placeholders::_1,
				std::placeholders::_2, std::placeholders::_3,
				std::tuple<>()));
		}

		template<class Signature, typename Function, typename Self>
		void register_member_impl(const std::string& name, const Function& f, Self* self)
		{
			// instantiate and store the invoker by name
			this->map_invokers.emplace(name, std::bind(&invoker<Function, Signature>::template call_member<std::tuple<>, Self>, f, self, std::placeholders::_1,
				std::placeholders::_2, std::placeholders::_3,
				std::tuple<>()));
		}

	private:
		template<typename Function, class Signature = Function, size_t N = function_traits<Signature>::arity>
		struct invoker;

		template<typename Function, class Signature, size_t N>
		struct invoker
		{
			// add an argument to a Fusion cons-list for each parameter type
			template<typename Args>
			static inline bool call(const Function& func, Request& req, Response& res, token_parser & parser, const Args& args)
			{
				if (N != parser.size() + 2)
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				typedef typename function_traits<Signature>::template args<N-1>::type arg_type;
				typename std::decay<arg_type>::type param;
				if (!parser.get<arg_type>(param))
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}
				return HTTPRouter::invoker<Function, Signature, N - 1>::call(func, req, res, parser, std::tuple_cat(std::make_tuple(param), args));
			}

			template<typename Args, typename Self>
			static inline bool call_member(Function func, Self* self, Request& req, Response& res, token_parser & parser, const Args& args)
			{
				if (N != parser.size() + 2)
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				typedef typename function_traits<Signature>::template args<N-1>::type arg_type;
				typename std::decay<arg_type>::type param;
				if (!parser.get<arg_type>(param))
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}
				return HTTPRouter::invoker<Function, Signature, N - 1>::call_member(func, self, req, res, parser, std::tuple_cat(std::make_tuple(param), args));
			}
		};

		template<typename Function, class Signature>
		struct invoker<Function, Signature, 2>
		{
			// the argument list is complete, now call the function
			template<typename Args>
			static inline bool call(const Function& func, Request& req, Response& res, token_parser &parser, const Args& args)
			{
				if (function_traits<Signature>::arity == 2 && !parser.empty())
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				apply(func, req, res, args);
				return true;
			}

			template<typename Args, typename Self>
			static inline bool call_member(const Function& func, Self* self, Request& req, Response& res, token_parser &parser, const Args& args)
			{
				if (function_traits<Signature>::arity == 2 && !parser.empty())
				{
					res.context().emplace(PARAM_ERROR, 0);
					return false;
				}

				apply_member(func, self, req, res, args);
				return true;
			}
		};

		template<int...>
		struct IndexTuple{};

		template<int N, int... Indexes>
		struct MakeIndexes : MakeIndexes<N - 1, N - 1, Indexes...>{};

		template<int... indexes>
		struct MakeIndexes<0, indexes...>
		{
			typedef IndexTuple<indexes...> type;
		};

		template<typename F, int ... Indexes, typename ... Args>
		static void apply_helper(const F& f, Request& req, Response& res, IndexTuple<Indexes...>, const std::tuple<Args...>& tup)
		{
			f(req, res, std::get<Indexes>(tup)...);
		}

		template<typename F, typename ... Args>
		static void apply(const F& f, Request& req, Response& res, const std::tuple<Args...>& tp)
		{
			apply_helper(f, req, res, typename MakeIndexes<sizeof... (Args)>::type(), tp);
		}

		template<typename F, typename Self, int ... Indexes, typename ... Args>
		static void apply_helper_member(const F& f, Self* self, Request& req, Response& res, IndexTuple<Indexes...>, const std::tuple<Args...>& tup)
		{
			(*self.*f)(req, res, std::get<Indexes>(tup)...);
		}

		template<typename F, typename Self, typename ... Args>
		static void apply_member(const F& f, Self* self, Request& req, Response& res, const std::tuple<Args...>& tp)
		{
			apply_helper_member(f, self, req, res, typename MakeIndexes<sizeof... (Args)>::type(), tp);
		}

	private:
		std::multimap<std::string, invoker_function> map_invokers;
		token_parser parser_;
		const static int PARAM_ERROR = -9999;
	};
}
<|endoftext|>


<commit_before><commit_msg>For iOS we already hardocde the inifile as rc in the .app directory<commit_after><|endoftext|>


<commit_before><commit_msg>LOK: Corner case with working dir as '/'.<commit_after><|endoftext|>


<commit_before>#include "bloomierFilter.h"

BloomierFilter::BloomierFilter(size_t pM, size_t pK, size_t pQ){
	mM = pM;;
	mK = pK;
	mQ = pQ;
	mBitVectorSize = ceil(pQ / static_cast<float>(CHAR_BIT));
	mBloomierHash = new BloomierHash(pM, pK, mBitVectorSize);
	mOrderAndMatchFinder = new OrderAndMatchFinder(pM, pK, mBloomierHash);
	mTable = new bloomierTable(pM);
	mValueTable = new vvsize_t_p(pM);
	for (size_t i = 0; i < pM; ++i) {
		(*mTable)[i] = new bitVector(mBitVectorSize, 0);
		(*mValueTable)[i] = new vsize_t();
	}

    mEncoder = new Encoder(mBitVectorSize);
	mPiIndex = 0;
}

BloomierFilter::~BloomierFilter(){

}
void BloomierFilter::check() {
	std::cout << __LINE__ << std::endl;
	size_t sumTable = 0;
	for(size_t i = 0; i < mTable->size(); ++i) {
        try {
		  sumTable += (*mTable)[i]->size();
        } catch(int e) {
            std::cout << "i: " << i << std::endl;
        }
	}
	std::cout << __LINE__ << std::endl;
	size_t sumValueTable = 0;
	for(size_t i = 0; i < mValueTable->size(); ++i) {
		sumValueTable += (*mValueTable)[i]->size();
	}
	std::cout << "sumTable: "  << sumTable << std::endl;
	std::cout << "sumValueTable: "  << sumValueTable << std::endl;

	std::cout << __LINE__ << std::endl;

}
bloomierTable* BloomierFilter::getTable() {
	return mTable;
}

void BloomierFilter::setTable(bloomierTable* pTable) {
    if (mTable != NULL) {
        for (size_t i = 0; i < mTable->size(); ++i) {
            delete (*mTable)[i];
        }
        delete mTable;
    }
	mTable = pTable;
}

vvsize_t_p* BloomierFilter::getValueTable() {
	return mValueTable;
}
void BloomierFilter::setValueTable(vvsize_t_p* pTable) {
	mValueTable = pTable;
}

void BloomierFilter::xorOperation(bitVector* pValue, bitVector* pMask, vsize_t* pNeighbors) {
	this->xorBitVector(pValue, pMask);

	for (auto it = pNeighbors->begin(); it != pNeighbors->end(); ++it) {
		if (*it < mTable->size()) {
			this->xorBitVector(pValue, (*mTable)[(*it)]);
		}
	}
}
vsize_t* BloomierFilter::get(size_t pKey) {
    // std::cout << __LINE__ << std::endl;
	vsize_t* neighbors = mBloomierHash->getKNeighbors(pKey);
	bitVector* mask = mBloomierHash->getMask(pKey);
	bitVector* valueToGet = new bitVector(mBitVectorSize, 0);
	this->xorOperation(valueToGet, mask, neighbors);

	size_t h = mEncoder->decode(valueToGet);
	if (h < neighbors->size()) {
		size_t L = (*neighbors)[h];
		if (L < mValueTable->size()) {
            delete neighbors;
			delete mask;
			delete valueToGet;
			return (*mValueTable)[L];
		}
	}
    delete neighbors;
	delete mask;
	delete valueToGet;
	return new vsize_t();
}
bool BloomierFilter::set(size_t pKey, size_t pValue) {
	vsize_t* neighbors = mBloomierHash->getKNeighbors(pKey);
	bitVector* mask = mBloomierHash->getMask(pKey);
	bitVector* valueToGet = new bitVector(mBitVectorSize, 0);
	this->xorOperation(valueToGet, mask, neighbors);
	size_t h = mEncoder->decode(valueToGet);

	delete mask;
	delete valueToGet;
	if (h < neighbors->size()) {
		size_t L = (*neighbors)[h];
		delete neighbors;
		if (L < mValueTable->size()) {
			vsize_t* v = ((*mValueTable)[L]);
			v->push_back(pValue);
			return true;
		}
	} else {
		delete neighbors;
		vsize_t* keys = new vsize_t (1, pKey);
		vvsize_t_p* values = new vvsize_t_p (1);
		(*values)[0] = new vsize_t(1, pValue);
		this->create(keys, values, mPiIndex);
		return true;
	}
	return false;
}

void BloomierFilter::create(vsize_t* pKeys, vvsize_t_p* pValues, size_t piIndex) {
	mOrderAndMatchFinder->find(pKeys);
    vsize_t* piVector = mOrderAndMatchFinder->getPiVector();
	vsize_t* tauVector = mOrderAndMatchFinder->getTauVector();
	for (size_t i = piIndex; i < piVector->size(); ++i) {
		vsize_t* neighbors = mBloomierHash->getKNeighbors((*pKeys)[i]);
		bitVector* mask = mBloomierHash->getMask((*pKeys)[i]);
		size_t l = (*tauVector)[i];
		size_t L = (*neighbors)[l];

		bitVector* encodeValue = mEncoder->encode(l);
		this->xorBitVector((*mTable)[L], encodeValue);
		this->xorBitVector((*mTable)[L], mask);
		for (size_t j = 0; j < neighbors->size(); ++j) {
			if (j != l) {
				this->xorBitVector((*mTable)[L], (*mTable)[(*neighbors)[j]]);
			}
		}
        for (size_t j = 0; j < (*pValues)[i-piIndex]->size(); ++j) {
            (*mValueTable)[L]->push_back((*pValues)[i-piIndex]->operator[](j));
        }
		delete neighbors;
		delete mask;
		delete encodeValue;
	}
	mPiIndex += pKeys->size();
	delete pKeys;
	for (size_t i = 0; i < pValues->size(); ++i) {
		delete (*pValues)[i];
	}
	delete pValues;
	// delete piVector;
	// delete tauVector;

}

void BloomierFilter::xorBitVector(bitVector* pResult, bitVector* pInput) {
	size_t length = std::min(pResult->size(), pInput->size());
	for (size_t i = 0; i < length; ++i) {
		(*pResult)[i] = (*pResult)[i] ^ (*pInput)[i];
	}
}<commit_msg>Added a hashSeed<commit_after>#include "bloomierFilter.h"

BloomierFilter::BloomierFilter(size_t pM, size_t pK, size_t pQ, size_t pHashSeed){
	mM = pM;;
	mK = pK;
	mQ = pQ;
	mBitVectorSize = ceil(pQ / static_cast<float>(CHAR_BIT));
	mBloomierHash = new BloomierHash(pM, pK, mBitVectorSize, pHashSeed);
	mOrderAndMatchFinder = new OrderAndMatchFinder(pM, pK, mBloomierHash);
	mTable = new bloomierTable(pM);
	mValueTable = new vvsize_t_p(pM);
	for (size_t i = 0; i < pM; ++i) {
		(*mTable)[i] = new bitVector(mBitVectorSize, 0);
		(*mValueTable)[i] = new vsize_t();
	}

    mEncoder = new Encoder(mBitVectorSize);
	mPiIndex = 0;
}

BloomierFilter::~BloomierFilter(){

}
void BloomierFilter::check() {
	std::cout << __LINE__ << std::endl;
	size_t sumTable = 0;
	for(size_t i = 0; i < mTable->size(); ++i) {
        try {
		  sumTable += (*mTable)[i]->size();
        } catch(int e) {
            std::cout << "i: " << i << std::endl;
        }
	}
	std::cout << __LINE__ << std::endl;
	size_t sumValueTable = 0;
	for(size_t i = 0; i < mValueTable->size(); ++i) {
		sumValueTable += (*mValueTable)[i]->size();
	}
	std::cout << "sumTable: "  << sumTable << std::endl;
	std::cout << "sumValueTable: "  << sumValueTable << std::endl;

	std::cout << __LINE__ << std::endl;

}
bloomierTable* BloomierFilter::getTable() {
	return mTable;
}

void BloomierFilter::setTable(bloomierTable* pTable) {
    if (mTable != NULL) {
        for (size_t i = 0; i < mTable->size(); ++i) {
            delete (*mTable)[i];
        }
        delete mTable;
    }
	mTable = pTable;
}

vvsize_t_p* BloomierFilter::getValueTable() {
	return mValueTable;
}
void BloomierFilter::setValueTable(vvsize_t_p* pTable) {
	mValueTable = pTable;
}

void BloomierFilter::xorOperation(bitVector* pValue, bitVector* pMask, vsize_t* pNeighbors) {
	this->xorBitVector(pValue, pMask);

	for (auto it = pNeighbors->begin(); it != pNeighbors->end(); ++it) {
		if (*it < mTable->size()) {
			this->xorBitVector(pValue, (*mTable)[(*it)]);
		}
	}
}
vsize_t* BloomierFilter::get(size_t pKey) {
    // std::cout << __LINE__ << std::endl;
	vsize_t* neighbors = mBloomierHash->getKNeighbors(pKey);
	bitVector* mask = mBloomierHash->getMask(pKey);
	bitVector* valueToGet = new bitVector(mBitVectorSize, 0);
	this->xorOperation(valueToGet, mask, neighbors);

	size_t h = mEncoder->decode(valueToGet);
	if (h < neighbors->size()) {
		size_t L = (*neighbors)[h];
		if (L < mValueTable->size()) {
            delete neighbors;
			delete mask;
			delete valueToGet;
			return (*mValueTable)[L];
		}
	}
    delete neighbors;
	delete mask;
	delete valueToGet;
	return new vsize_t();
}
bool BloomierFilter::set(size_t pKey, size_t pValue) {
	vsize_t* neighbors = mBloomierHash->getKNeighbors(pKey);
	bitVector* mask = mBloomierHash->getMask(pKey);
	bitVector* valueToGet = new bitVector(mBitVectorSize, 0);
	this->xorOperation(valueToGet, mask, neighbors);
	size_t h = mEncoder->decode(valueToGet);

	delete mask;
	delete valueToGet;
	if (h < neighbors->size()) {
		size_t L = (*neighbors)[h];
		delete neighbors;
		if (L < mValueTable->size()) {
			vsize_t* v = ((*mValueTable)[L]);
			v->push_back(pValue);
			return true;
		}
	} else {
		delete neighbors;
		vsize_t* keys = new vsize_t (1, pKey);
		vvsize_t_p* values = new vvsize_t_p (1);
		(*values)[0] = new vsize_t(1, pValue);
		this->create(keys, values, mPiIndex);
		return true;
	}
	return false;
}

void BloomierFilter::create(vsize_t* pKeys, vvsize_t_p* pValues, size_t piIndex) {
	mOrderAndMatchFinder->find(pKeys);
    vsize_t* piVector = mOrderAndMatchFinder->getPiVector();
	vsize_t* tauVector = mOrderAndMatchFinder->getTauVector();
	for (size_t i = piIndex; i < piVector->size(); ++i) {
		vsize_t* neighbors = mBloomierHash->getKNeighbors((*pKeys)[i]);
		bitVector* mask = mBloomierHash->getMask((*pKeys)[i]);
		size_t l = (*tauVector)[i];
		size_t L = (*neighbors)[l];

		bitVector* encodeValue = mEncoder->encode(l);
		this->xorBitVector((*mTable)[L], encodeValue);
		this->xorBitVector((*mTable)[L], mask);
		for (size_t j = 0; j < neighbors->size(); ++j) {
			if (j != l) {
				this->xorBitVector((*mTable)[L], (*mTable)[(*neighbors)[j]]);
			}
		}
        for (size_t j = 0; j < (*pValues)[i-piIndex]->size(); ++j) {
            (*mValueTable)[L]->push_back((*pValues)[i-piIndex]->operator[](j));
        }
		delete neighbors;
		delete mask;
		delete encodeValue;
	}
	mPiIndex += pKeys->size();
	delete pKeys;
	for (size_t i = 0; i < pValues->size(); ++i) {
		delete (*pValues)[i];
	}
	delete pValues;
	// delete piVector;
	// delete tauVector;

}

void BloomierFilter::xorBitVector(bitVector* pResult, bitVector* pInput) {
	size_t length = std::min(pResult->size(), pInput->size());
	for (size_t i = 0; i < length; ++i) {
		(*pResult)[i] = (*pResult)[i] ^ (*pInput)[i];
	}
}<|endoftext|>


<commit_before>/**
 * thrift - a lightweight cross-language rpc/serialization tool
 *
 * This file contains the main compiler engine for Thrift, which invokes the
 * scanner/parser to build the thrift object tree. The interface generation
 * code for each language lives in a file by the language name.
 *
 * @author Mark Slee <mcslee@facebook.com>
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>

// Careful: must include globals first
#include "globals.h"

#include "main.h"
#include "parse/t_program.h"
#include "generate/t_cpp_generator.h"
#include "generate/t_java_generator.h"
#include "generate/t_php_generator.h"
#include "generate/t_py_generator.h"

using namespace std;

/** Global program tree */
t_program* g_program;

/** Global debug state */
int g_debug = 0;

/** Global time string */
char* g_time_str;

/**
 * Report an error to the user. This is called yyerror for historical
 * reasons (lex and yacc expect the error reporting routine to be called
 * this). Call this function to report any errors to the user.
 * yyerror takes printf style arguments.
 *
 * @param fmt C format string followed by additional arguments
 */
void yyerror(char* fmt, ...) {
  va_list args;
  fprintf(stderr,
          "\n!!! Error: line %d (last token was '%s')",
          yylineno,
          yytext);
  fprintf(stderr, "\n!!! ");

  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);

  fprintf(stderr, "\n");
}

/**
 * Prints a debug message from the parser.
 *
 * @param fmt C format string followed by additional arguments
 */
void pdebug(char* fmt, ...) {
  if (g_debug == 0) {
    return;
  }
  va_list args;
  printf("[Parse] ");
  va_start(args, fmt);
  vprintf(fmt, args);
  va_end(args);
  printf("\n");
}

/**
 * Prints a failure message and exits
 *
 * @param fmt C format string followed by additional arguments
 */
void failure(char* fmt, ...) {
  va_list args;
  fprintf(stderr, "\n!!! Failure: ");
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);
  printf("\n");
  exit(1);
}

/**
 * Diplays the usage message and then exits with an error code.
 */
void usage() {
  fprintf(stderr, "Usage: thrift [options] file\n");
  fprintf(stderr, "Options:\n");
  fprintf(stderr, "  --cpp    Generate C++ output files\n");
  fprintf(stderr, "  --java   Generate Java output files\n");
  fprintf(stderr, "  --php    Generate PHP output files\n");
  fprintf(stderr, "  --phpi   Generate PHP inlined files\n");
  fprintf(stderr, "  --py     Generate Python output files\n");
  fprintf(stderr, "  --debug  Print parse debugging to standard output\n");
  exit(1);
}

/**
 * Parse it up.. then spit it back out, in pretty much every language
 */
int main(int argc, char** argv) {
  int i;
  bool gen_cpp = false;
  bool gen_java = false;
  bool gen_py = false;
  bool gen_php = false;
  bool php_inline = false;

  // Setup time string
  time_t now = time(NULL);
  g_time_str = ctime(&now);

  // Check for necessary arguments
  if (argc < 2) {
    usage();
  }

  for (i = 1; i < argc-1; i++) {
    if (strcmp(argv[i], "--debug") == 0) {
      g_debug = 1;
    } else if (strcmp(argv[i], "--cpp") == 0) {
      gen_cpp = true;
    } else if (strcmp(argv[i], "--java") == 0) {
      gen_java = true;
    } else if (strcmp(argv[i], "--php") == 0) {
      gen_php = true;
      php_inline = false;
    } else if (strcmp(argv[i], "--phpi") == 0) {
      gen_php = true;
      php_inline = true;
    } else if (strcmp(argv[i], "--py") == 0) {
      gen_py = true;
    } else {
      fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
      usage();
    }
  }

  if (!gen_cpp && !gen_java && !gen_php && !gen_py) {
    fprintf(stderr, "!!! No output language(s) specified\n\n");
    usage();
  }

  // Open input file
  char* input_file = argv[i];
  yyin = fopen(input_file, "r");
  if (yyin == 0) {
    failure("Could not open input file: \"%s\"", input_file);
  }

  // Extract program name by dropping directory and .thrift from filename
  string name = input_file;
  string::size_type slash = name.rfind("/");
  if (slash != string::npos) {
    name = name.substr(slash+1);
  }
  string::size_type dot = name.find(".");
  if (dot != string::npos) {
    name = name.substr(0, dot);
  }

  // Parse it
  g_program = new t_program(name);

  if (yyparse() != 0) {
    failure("Parser error.");
  }

  // Generate code
  try {
    if (gen_cpp) {
      t_cpp_generator* cpp = new t_cpp_generator();
      cpp->generate_program(g_program);
      delete cpp;
    }

    if (gen_java) {
      t_java_generator* java = new t_java_generator();
      java->generate_program(g_program);
      delete java;
    }

    if (gen_php) {
      t_php_generator* php = new t_php_generator(php_inline);
      php->generate_program(g_program);
      delete php;
    }

    if (gen_py) {
      t_py_generator* py = new t_py_generator();
      py->generate_program(g_program);
      delete py;
    }
  } catch (string s) {
    printf("Error: %s\n", s.c_str());
  } catch (const char* exc) {
    printf("Error: %s\n", exc);
  }

  // Clean up
  delete g_program;

  // Finished
  return 0;
}
<commit_msg>Thrift compiler to tokenize args by " " so you can use script files<commit_after>/**
 * thrift - a lightweight cross-language rpc/serialization tool
 *
 * This file contains the main compiler engine for Thrift, which invokes the
 * scanner/parser to build the thrift object tree. The interface generation
 * code for each language lives in a file by the language name.
 *
 * @author Mark Slee <mcslee@facebook.com>
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>

// Careful: must include globals first
#include "globals.h"

#include "main.h"
#include "parse/t_program.h"
#include "generate/t_cpp_generator.h"
#include "generate/t_java_generator.h"
#include "generate/t_php_generator.h"
#include "generate/t_py_generator.h"

using namespace std;

/** Global program tree */
t_program* g_program;

/** Global debug state */
int g_debug = 0;

/** Global time string */
char* g_time_str;

/**
 * Report an error to the user. This is called yyerror for historical
 * reasons (lex and yacc expect the error reporting routine to be called
 * this). Call this function to report any errors to the user.
 * yyerror takes printf style arguments.
 *
 * @param fmt C format string followed by additional arguments
 */
void yyerror(char* fmt, ...) {
  va_list args;
  fprintf(stderr,
          "\n!!! Error: line %d (last token was '%s')",
          yylineno,
          yytext);
  fprintf(stderr, "\n!!! ");

  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);

  fprintf(stderr, "\n");
}

/**
 * Prints a debug message from the parser.
 *
 * @param fmt C format string followed by additional arguments
 */
void pdebug(char* fmt, ...) {
  if (g_debug == 0) {
    return;
  }
  va_list args;
  printf("[Parse] ");
  va_start(args, fmt);
  vprintf(fmt, args);
  va_end(args);
  printf("\n");
}

/**
 * Prints a failure message and exits
 *
 * @param fmt C format string followed by additional arguments
 */
void failure(char* fmt, ...) {
  va_list args;
  fprintf(stderr, "\n!!! Failure: ");
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);
  printf("\n");
  exit(1);
}

/**
 * Diplays the usage message and then exits with an error code.
 */
void usage() {
  fprintf(stderr, "Usage: thrift [options] file\n");
  fprintf(stderr, "Options:\n");
  fprintf(stderr, "  --cpp    Generate C++ output files\n");
  fprintf(stderr, "  --java   Generate Java output files\n");
  fprintf(stderr, "  --php    Generate PHP output files\n");
  fprintf(stderr, "  --phpi   Generate PHP inlined files\n");
  fprintf(stderr, "  --py     Generate Python output files\n");
  fprintf(stderr, "  --debug  Print parse debugging to standard output\n");
  exit(1);
}

/**
 * Parse it up.. then spit it back out, in pretty much every language
 */
int main(int argc, char** argv) {
  int i;
  bool gen_cpp = false;
  bool gen_java = false;
  bool gen_py = false;
  bool gen_php = false;
  bool php_inline = false;

  // Setup time string
  time_t now = time(NULL);
  g_time_str = ctime(&now);

  // Check for necessary arguments
  if (argc < 2) {
    usage();
  }

  for (i = 1; i < argc-1; i++) {
    char* arg;
    arg = strtok(argv[i], " ");
    while (arg != NULL) {
      if (strcmp(arg, "--debug") == 0) {
        g_debug = 1;
      } else if (strcmp(arg, "--cpp") == 0) {
        gen_cpp = true;
      } else if (strcmp(arg, "--java") == 0) {
        gen_java = true;
      } else if (strcmp(arg, "--php") == 0) {
        gen_php = true;
        php_inline = false;
      } else if (strcmp(arg, "--phpi") == 0) {
        gen_php = true;
        php_inline = true;
      } else if (strcmp(arg, "--py") == 0) {
        gen_py = true;
      } else {
        fprintf(stderr, "!!! Unrecognized option: %s\n", arg);
        usage();
      }

      // Tokenize more
      arg = strtok(NULL, " ");
    }
  }

  if (!gen_cpp && !gen_java && !gen_php && !gen_py) {
    fprintf(stderr, "!!! No output language(s) specified\n\n");
    usage();
  }

  // Open input file
  char* input_file = argv[i];
  yyin = fopen(input_file, "r");
  if (yyin == 0) {
    failure("Could not open input file: \"%s\"", input_file);
  }

  // Extract program name by dropping directory and .thrift from filename
  string name = input_file;
  string::size_type slash = name.rfind("/");
  if (slash != string::npos) {
    name = name.substr(slash+1);
  }
  string::size_type dot = name.find(".");
  if (dot != string::npos) {
    name = name.substr(0, dot);
  }

  // Parse it
  g_program = new t_program(name);

  if (yyparse() != 0) {
    failure("Parser error.");
  }

  // Generate code
  try {
    if (gen_cpp) {
      t_cpp_generator* cpp = new t_cpp_generator();
      cpp->generate_program(g_program);
      delete cpp;
    }

    if (gen_java) {
      t_java_generator* java = new t_java_generator();
      java->generate_program(g_program);
      delete java;
    }

    if (gen_php) {
      t_php_generator* php = new t_php_generator(php_inline);
      php->generate_program(g_program);
      delete php;
    }

    if (gen_py) {
      t_py_generator* py = new t_py_generator();
      py->generate_program(g_program);
      delete py;
    }
  } catch (string s) {
    printf("Error: %s\n", s.c_str());
  } catch (const char* exc) {
    printf("Error: %s\n", exc);
  }

  // Clean up
  delete g_program;

  // Finished
  return 0;
}
<|endoftext|>


<commit_before>/**
 * \file
 * \brief FifoQueue class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-12-10
 */

#ifndef INCLUDE_DISTORTOS_FIFOQUEUE_HPP_
#define INCLUDE_DISTORTOS_FIFOQUEUE_HPP_

#include "distortos/scheduler/FifoQueueBase.hpp"

namespace distortos
{

/**
 * \brief FifoQueue class is a simple FIFO queue for thread-thread, thread-interrupt or interrupt-interrupt
 * communication. It supports multiple readers and multiple writers. It is implemented as a thin wrapper for
 * scheduler::FifoQueueBase.
 *
 * \param T is the type of data in queue
 */

template<typename T>
class FifoQueue : private scheduler::FifoQueueBase
{
public:

	/// type of uninitialized storage for data
	using Storage = Storage<T>;

	/**
	 * \brief FifoQueue's constructor
	 *
	 * \param [in] storage is an array of Storage elements
	 * \param [in] maxElements is the number of elements in storage array
	 */

	FifoQueue(Storage* const storage, const size_t maxElements) :
			FifoQueueBase{storage, maxElements, TypeTag<T>{}}
	{

	}

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::pop(T&)
	 *
	 * \param [out] value is a reference to object that will be used to return popped value, its contents are swapped
	 * with the value in the queue's storage and destructed when no longer needed
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int pop(T& value)
	{
		return FifoQueueBase::pop(value);
	}

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::push(const T&)
	 *
	 * \param [in] value is a reference to object that will be pushed, value in queue's storage is copy-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int push(const T& value)
	{
		return FifoQueueBase::push(value);
	}

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::push(T&&)
	 *
	 * \param [in] value is a rvalue reference to object that will be pushed, value in queue's storage is
	 * move-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int push(T&& value)
	{
		return FifoQueueBase::push(std::move(value));
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPop(T&)
	 *
	 * \param [out] value is a reference to object that will be used to return popped value, its contents are swapped
	 * with the value in the queue's storage and destructed when no longer needed
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPop(T& value)
	{
		return FifoQueueBase::tryPop(value);
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPopFor(TickClock::duration, T&)
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] value is a reference to object that will be used to return popped value, its contents are swapped
	 * with the value in the queue's storage and destructed when no longer needed
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPopFor(const TickClock::duration duration, T& value)
	{
		return FifoQueueBase::tryPopFor(duration, value);
	}

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPush(const T&)
	 *
	 * \param [in] value is a reference to object that will be pushed, value in queue's storage is copy-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPush(const T& value)
	{
		return FifoQueueBase::tryPush(value);
	}

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPush(T&&)
	 *
	 * \param [in] value is a rvalue reference to object that will be pushed, value in queue's storage is
	 * move-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPush(T&& value)
	{
		return FifoQueueBase::tryPush(std::move(value));
	}

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPushFor(TickClock::duration, const T&)
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] value is a reference to object that will be pushed, value in queue's storage is copy-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPushFor(const TickClock::duration duration, const T& value)
	{
		return FifoQueueBase::tryPushFor(duration, value);
	}
};

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_FIFOQUEUE_HPP_
<commit_msg>FifoQueue: add FifoQueue::tryPushFor(TickClock::duration, T&&)<commit_after>/**
 * \file
 * \brief FifoQueue class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-12-10
 */

#ifndef INCLUDE_DISTORTOS_FIFOQUEUE_HPP_
#define INCLUDE_DISTORTOS_FIFOQUEUE_HPP_

#include "distortos/scheduler/FifoQueueBase.hpp"

namespace distortos
{

/**
 * \brief FifoQueue class is a simple FIFO queue for thread-thread, thread-interrupt or interrupt-interrupt
 * communication. It supports multiple readers and multiple writers. It is implemented as a thin wrapper for
 * scheduler::FifoQueueBase.
 *
 * \param T is the type of data in queue
 */

template<typename T>
class FifoQueue : private scheduler::FifoQueueBase
{
public:

	/// type of uninitialized storage for data
	using Storage = Storage<T>;

	/**
	 * \brief FifoQueue's constructor
	 *
	 * \param [in] storage is an array of Storage elements
	 * \param [in] maxElements is the number of elements in storage array
	 */

	FifoQueue(Storage* const storage, const size_t maxElements) :
			FifoQueueBase{storage, maxElements, TypeTag<T>{}}
	{

	}

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::pop(T&)
	 *
	 * \param [out] value is a reference to object that will be used to return popped value, its contents are swapped
	 * with the value in the queue's storage and destructed when no longer needed
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int pop(T& value)
	{
		return FifoQueueBase::pop(value);
	}

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::push(const T&)
	 *
	 * \param [in] value is a reference to object that will be pushed, value in queue's storage is copy-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int push(const T& value)
	{
		return FifoQueueBase::push(value);
	}

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::push(T&&)
	 *
	 * \param [in] value is a rvalue reference to object that will be pushed, value in queue's storage is
	 * move-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int push(T&& value)
	{
		return FifoQueueBase::push(std::move(value));
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPop(T&)
	 *
	 * \param [out] value is a reference to object that will be used to return popped value, its contents are swapped
	 * with the value in the queue's storage and destructed when no longer needed
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPop(T& value)
	{
		return FifoQueueBase::tryPop(value);
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPopFor(TickClock::duration, T&)
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] value is a reference to object that will be used to return popped value, its contents are swapped
	 * with the value in the queue's storage and destructed when no longer needed
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPopFor(const TickClock::duration duration, T& value)
	{
		return FifoQueueBase::tryPopFor(duration, value);
	}

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPush(const T&)
	 *
	 * \param [in] value is a reference to object that will be pushed, value in queue's storage is copy-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPush(const T& value)
	{
		return FifoQueueBase::tryPush(value);
	}

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPush(T&&)
	 *
	 * \param [in] value is a rvalue reference to object that will be pushed, value in queue's storage is
	 * move-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPush(T&& value)
	{
		return FifoQueueBase::tryPush(std::move(value));
	}

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPushFor(TickClock::duration, const T&)
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] value is a reference to object that will be pushed, value in queue's storage is copy-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPushFor(const TickClock::duration duration, const T& value)
	{
		return FifoQueueBase::tryPushFor(duration, value);
	}

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * Wrapper for scheduler::FifoQueueBase::tryPushFor(TickClock::duration, T&&)
	 *
	 * \param [in] duration is the duration after which the call will be terminated without pushing the element
	 * \param [in] value is a rvalue reference to object that will be pushed, value in queue's storage is
	 * move-constructed
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPushFor(const TickClock::duration duration, T&& value)
	{
		return FifoQueueBase::tryPushFor(duration, std::move(value));
	}
};

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_FIFOQUEUE_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <map>
#include <iostream>
#include <fstream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "driver.h"
#include "passes.h"
#include "symbol.h"
#include "expr.h"
#include "stmt.h"
#include "docs.h"
#include "mysystem.h"
#include "stringutil.h"
#include "scopeResolve.h"
#include "AstToText.h"
#include "AstPrintDocs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // To handle inheritance, we need to look up parent classes and records.
    // In order to be successful when looking up these parents, the import
    // expressions should be accurately accounted for.
    addToSymbolTable(gDefExprs);
    processImportExprs();

    // Open the directory to store the docs
    std::string docsDir = (strlen(fDocsFolder) != 0) ? fDocsFolder : "docs";
    std::string docsFolderName = docsDir;

    if (!fDocsTextOnly) {
      docsFolderName = generateSphinxProject(docsDir);
    }

    mkdir(docsFolderName.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsFolderName);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsDir);
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void inheritance(Vec<AggregateType*> *list, AggregateType *cl) {
  for_alist(expr, cl->inherits) {
    AggregateType* pt = discoverParentAndCheck(expr, cl);

    list->add_exclusive(pt);
    inheritance(list, pt);
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }

    Vec<AggregateType*> superClasses;
    inheritance(&superClasses, cl);

    if (fDocsAlphabetize)
      qsort(superClasses.v, superClasses.n, sizeof(superClasses.v[0]), compareClasses);

    forv_Vec(AggregateType, superClass, superClasses) {
      superClass->printInheritanceDocs(file, tabs + 1);
      printFields(file, superClass, tabs + 2);

      forv_Vec(FnSymbol, fn, superClass->methods) {
        fn->printDocs(file, tabs + 2);
      }
      *file << std::endl;
    }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // FIXME: This ought to be done in a TMPDIR, unless --save-rst is
  //        provided... (thomasvandoren, 2015-01-29)

  // Create the output dir under the docs output dir.
  const char * htmldir = astr(dirpath.c_str(), "/html");

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", htmldir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", htmldir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(htmldir, "/source/modules");
  return std::string(moddir);
}

/* Call `make html` from inside sphinx project. */
void generateSphinxOutput(std::string dirpath) {
  const char * htmldir = astr(dirpath.c_str(), "/html");

  // The virtualenv activate script is at:
  //   $CHPL_HOME/third-party/chpldoc-venv/install/$CHPL_TARGET_PLATFORM/chpldoc-virtualenv/bin/activate
  const char * activate = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpdoc-virtualenv/bin/activate");

  // Run: `. $activate && cd $htmldir && $CHPL_MAKE html`
  const char * cmd = astr(
    ". ", activate,
    " && cd ", htmldir, " && ",
    CHPL_MAKE, " html");
  mysystem(cmd, "building html output from chpldoc sphinx project");
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsFolderName) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsFolderName + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsFolderName) {
  std::string filename = filenameFromMod(mod, docsFolderName);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<commit_msg>Comment out inheritance lines in docs.cpp.<commit_after>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <map>
#include <iostream>
#include <fstream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "driver.h"
#include "passes.h"
#include "symbol.h"
#include "expr.h"
#include "stmt.h"
#include "docs.h"
#include "mysystem.h"
#include "stringutil.h"
#include "scopeResolve.h"
#include "AstToText.h"
#include "AstPrintDocs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // To handle inheritance, we need to look up parent classes and records.
    // In order to be successful when looking up these parents, the import
    // expressions should be accurately accounted for.
    addToSymbolTable(gDefExprs);
    processImportExprs();

    // Open the directory to store the docs
    std::string docsDir = (strlen(fDocsFolder) != 0) ? fDocsFolder : "docs";
    std::string docsFolderName = docsDir;

    if (!fDocsTextOnly) {
      docsFolderName = generateSphinxProject(docsDir);
    }

    mkdir(docsFolderName.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsFolderName);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsDir);
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void inheritance(Vec<AggregateType*> *list, AggregateType *cl) {
  for_alist(expr, cl->inherits) {
    AggregateType* pt = discoverParentAndCheck(expr, cl);

    list->add_exclusive(pt);
    inheritance(list, pt);
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }

    // TODO: Restore the following lines as opt-in feature. They print the the
    //       "inherited from <blah>" line and all the inherited members and
    //       methods. (thomasvandoren, 2015-02-23)
    //
    // Vec<AggregateType*> superClasses;
    // inheritance(&superClasses, cl);

    // if (fDocsAlphabetize)
    //   qsort(superClasses.v, superClasses.n, sizeof(superClasses.v[0]), compareClasses);

    // forv_Vec(AggregateType, superClass, superClasses) {
    //   superClass->printInheritanceDocs(file, tabs + 1);
    //   printFields(file, superClass, tabs + 2);

    //   forv_Vec(FnSymbol, fn, superClass->methods) {
    //     fn->printDocs(file, tabs + 2);
    //   }
    //   *file << std::endl;
    // }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // FIXME: This ought to be done in a TMPDIR, unless --save-rst is
  //        provided... (thomasvandoren, 2015-01-29)

  // Create the output dir under the docs output dir.
  const char * htmldir = astr(dirpath.c_str(), "/html");

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", htmldir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", htmldir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(htmldir, "/source/modules");
  return std::string(moddir);
}

/* Call `make html` from inside sphinx project. */
void generateSphinxOutput(std::string dirpath) {
  const char * htmldir = astr(dirpath.c_str(), "/html");

  // The virtualenv activate script is at:
  //   $CHPL_HOME/third-party/chpldoc-venv/install/$CHPL_TARGET_PLATFORM/chpldoc-virtualenv/bin/activate
  const char * activate = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpdoc-virtualenv/bin/activate");

  // Run: `. $activate && cd $htmldir && $CHPL_MAKE html`
  const char * cmd = astr(
    ". ", activate,
    " && cd ", htmldir, " && ",
    CHPL_MAKE, " html");
  mysystem(cmd, "building html output from chpldoc sphinx project");
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsFolderName) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsFolderName + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsFolderName) {
  std::string filename = filenameFromMod(mod, docsFolderName);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<|endoftext|>