<commit_before>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <iostream>

#include "BitFunnel/Allocators/IAllocator.h"
#include "BitFunnel/Configuration/Factories.h"
#include "BitFunnel/Configuration/IFileSystem.h"
#include "BitFunnel/Configuration/IStreamConfiguration.h"
#include "BitFunnel/Exceptions.h"
#include "BitFunnel/IDiagnosticStream.h"
#include "BitFunnel/Index/Factories.h"
#include "BitFunnel/Index/IDocumentCache.h"
#include "BitFunnel/Index/IIngestor.h"
#include "BitFunnel/Plan/Factories.h"
#include "BitFunnel/Plan/IMatchVerifier.h"
#include "BitFunnel/Plan/QueryInstrumentation.h"
#include "BitFunnel/Plan/QueryParser.h"
#include "BitFunnel/Plan/ResultsBuffer.h"
#include "BitFunnel/Plan/TermMatchTreeEvaluator.h"
#include "BitFunnel/Utilities/Allocator.h"
#include "BitFunnel/Utilities/Factories.h"
#include "BitFunnel/Utilities/ReadLines.h"
#include "CsvTsv/Csv.h"
#include "Environment.h"
#include "VerifyCommand.h"

namespace BitFunnel
{
    //*************************************************************************
    //
    // Verify
    //
    //*************************************************************************
    Verify::Verify(Environment & environment,
                   Id id,
                   char const * parameters)
        : TaskBase(environment, id, Type::Synchronous)
    {
        auto command = TaskFactory::GetNextToken(parameters);
        if (command.compare("one") == 0)
        {
            m_isSingleQuery = true;
            m_isOutput = false;
            m_query = parameters;
        }
        else if (command.compare("log") == 0)
        {
            m_isSingleQuery = false;
            m_isOutput = false;
            m_query = TaskFactory::GetNextToken(parameters);
        }
        else if (command.compare("output") == 0)
        {
            m_isSingleQuery = false;
            m_isOutput = true;
            m_query = TaskFactory::GetNextToken(parameters);
        }
        else
        {
            RecoverableError error("Query expects \"one\" or \"log\".");
            throw error;
        }
    }

    // TODO: this should be somewhere else.
    std::unique_ptr<IMatchVerifier> VerifyOneQuery(
        Environment & environment,
        std::string query,
        bool runVerification)
    {
        static const size_t c_allocatorSize = 1ull << 16;
        Allocator allocator(c_allocatorSize);

        auto streamConfiguration = Factories::CreateStreamConfiguration();

        QueryParser parser(query.c_str(), *streamConfiguration, allocator);
        auto tree = parser.Parse();

        std::unique_ptr<IMatchVerifier> verifier =
            Factories::CreateMatchVerifier(query);

        if (tree == nullptr)
        {
            // std::cout << "Empty query." << std::endl;
        }
        else
        {
            // auto & environment = GetEnvironment();
            auto & cache = environment.GetIngestor().GetDocumentCache();
            auto & config = environment.GetConfiguration();
            TermMatchTreeEvaluator evaluator(config);

            size_t matchCount = 0;
            size_t documentCount = 0;

            if (runVerification)
            {
                for (auto entry : cache)
                {
                    ++documentCount;
                    bool matches = evaluator.Evaluate(*tree, entry.first);

                    if (matches)
                    {
                        ++matchCount;
                        //std::cout
                        //    << "  DocId(" << entry.second << ") "
                        //    << std::endl;

                        verifier->AddExpected(entry.second);
                    }
                }
            }

            // std::cout
            //     << matchCount << " match(es) out of "
            //     << documentCount << " documents."
            //     << std::endl;

            auto diagnosticStream = Factories::CreateDiagnosticStream(std::cout);
            // diagnosticStream->Enable("");

            QueryInstrumentation instrumentation;

            ResultsBuffer results(environment.GetSimpleIndex().GetIngestor().GetDocumentCount());

            Factories::RunQueryPlanner(*tree,
                                       environment.GetSimpleIndex(),
                                       allocator,
                                       *diagnosticStream,
                                       instrumentation,
                                       results);

            for (auto result : results)
            {
                DocumentHandle handle = Factories::CreateDocumentHandle(result.m_slice, result.m_index);
                verifier->AddObserved(handle.GetDocId());
            }

            verifier->Verify();
            //verifier->Print(std::cout);
        }
        return verifier;
    }

    void Verify::Execute()
    {
        if (m_isSingleQuery)
        {
            std::cout
                << "Processing query \""
                << m_query
                << "\"" << std::endl;
            auto verifier = VerifyOneQuery(GetEnvironment(), m_query, true);
            std::cout << "True positive count: "
                << verifier->GetTruePositiveCount()
                << std::endl
                << "False positive count: "
                << verifier->GetFalsePositiveCount()
                << std::endl
                << "False negative count: "
                << verifier->GetFalseNegativeCount()
                << std::endl;
            if (verifier->GetTruePositiveCount() > 0)
            {
                std::cout << "True positives:" << std::endl;
                for (const auto doc : verifier->GetTruePositives())
                {
                    std::cout << doc << ",";
                }
                std::cout << std::endl;
            }

            if (verifier->GetFalsePositiveCount() > 0)
            {
                std::cout << "False positives:" << std::endl;
                for (const auto doc : verifier->GetFalsePositives())
                {
                    std::cout << doc << ",";
                }
                std::cout << std::endl;
            }

            if (verifier->GetFalseNegativeCount() > 0)
            {
                std::cout << "False negatives:" << std::endl;
                for (const auto doc : verifier->GetFalseNegatives())
                {
                    std::cout << doc << ",";
                }
                std::cout << std::endl;

                throw RecoverableError("MatchVerifier: false negative detected.");
            }
        }
        else
        {
            std::cout
                << "Processing queries from log at \""
                << m_query
                << "\"" << std::endl;
            auto fileSystem = Factories::CreateFileSystem();  // TODO: Use environment file system
            auto queries = ReadLines(*fileSystem, m_query.c_str());

            // TODO: use FileManager.
            auto verificationOut = GetEnvironment().
                GetFileSystem().
                OpenForWrite("verificationOutput.csv");
            CsvTsv::CsvTableFormatter verificationFormatter(*verificationOut);
            CsvTsv::TableWriter writer(verificationFormatter);
            CsvTsv::OutputColumn<std::string>
                queryString("Query",
                            "Query text");
            CsvTsv::OutputColumn<uint64_t>
                docId("Document",
                      "ID of document.");
            CsvTsv::OutputColumn<uint64_t>
                type("Type",
                     "0: true positive. 1: false positive. 2: false negative. 3: unchecked result. TODO: fix this");

            writer.DefineColumn(queryString);
            writer.DefineColumn(docId);
            writer.DefineColumn(type);
            writer.WritePrologue();

            auto verificationSummary = GetEnvironment().
                GetFileSystem().
                OpenForWrite("verificationSummary.csv");
            CsvTsv::CsvTableFormatter summaryFormatter(*verificationSummary);
            CsvTsv::TableWriter summary(summaryFormatter);
            CsvTsv::OutputColumn<uint64_t>
                termPos("TermPos",
                        "Term position.");
            CsvTsv::OutputColumn<uint64_t>
                numTruePos("TruePositives",
                           "Number of true positives.");
            CsvTsv::OutputColumn<uint64_t>
                numFalsePos("FalsePositives",
                            "Number of false positives.");
            CsvTsv::OutputColumn<uint64_t>
                numFalseNeg("FalseNegatives",
                            "Number of true negatives.");
            CsvTsv::OutputColumn<double>
                falseRate("FalseRate",
                          "(Num false positives) / (Num total matches).");

            summary.DefineColumn(queryString);
            summary.DefineColumn(termPos);
            summary.DefineColumn(numTruePos);
            summary.DefineColumn(numFalsePos);
            summary.DefineColumn(numFalseNeg);
            summary.DefineColumn(falseRate);
            summary.WritePrologue();

            uint64_t position = 0;
            for (const auto & query : queries)
            {
                auto verifier = VerifyOneQuery(GetEnvironment(), query, !m_isOutput);
                queryString = verifier->GetQuery();

                if (!m_isOutput)
                {
                    std::vector<DocId> results = verifier->GetTruePositives();
                    numTruePos = results.size();
                    type = 0;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                    results = verifier->GetFalsePositives();
                    numFalsePos = results.size();
                    type = 1;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                    results = verifier->GetFalseNegatives();
                    numFalseNeg = results.size();
                    type = 2;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                    falseRate = static_cast<double>(numFalsePos) /
                        (static_cast<double>(numFalsePos) +
                         static_cast<double>(numTruePos));

                    summary.WriteDataRow();
                    ++position;
                    termPos = position;
                }
                else
                {
                    // TODO: fix this confusing setup. In m_isOutput mode, we
                    // never run the verifier and therefore never have
                    // "expected" results, which means that everything shows up
                    // as a false positive. This terminology conflict is because
                    // we added this mode after creating the verifier.
                    std::vector<DocId> results = verifier->GetFalsePositives();
                    type = 3;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                }
            }

            writer.WriteEpilogue();
            summary.WriteEpilogue();
        }
    }

    ICommand::Documentation Verify::GetDocumentation()
    {
        return Documentation(
            "verify",
            "Verifies the results of a single query against the document cache.",
            "verify (one <expression>) | (log <file>)\n"
            "  Verifies a single query or a list of queries\n"
            "  against the document cache.\n"
        );
    }
}
<commit_msg>WIP: All tests pass now. My machine must have had a build dependency issue. The debugger notified me that the sources were newer than the executable. All tests passed after a full rebuild.<commit_after>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <iostream>

#include "BitFunnel/Allocators/IAllocator.h"
#include "BitFunnel/Configuration/Factories.h"
#include "BitFunnel/Configuration/IFileSystem.h"
#include "BitFunnel/Configuration/IStreamConfiguration.h"
#include "BitFunnel/Exceptions.h"
#include "BitFunnel/IDiagnosticStream.h"
#include "BitFunnel/Index/Factories.h"
#include "BitFunnel/Index/IDocumentCache.h"
#include "BitFunnel/Index/IIngestor.h"
#include "BitFunnel/Plan/Factories.h"
#include "BitFunnel/Plan/IMatchVerifier.h"
#include "BitFunnel/Plan/QueryInstrumentation.h"
#include "BitFunnel/Plan/QueryParser.h"
#include "BitFunnel/Plan/ResultsBuffer.h"
#include "BitFunnel/Plan/TermMatchTreeEvaluator.h"
#include "BitFunnel/Utilities/Allocator.h"
#include "BitFunnel/Utilities/Factories.h"
#include "BitFunnel/Utilities/ReadLines.h"
#include "CsvTsv/Csv.h"
#include "Environment.h"
#include "VerifyCommand.h"

namespace BitFunnel
{
    //*************************************************************************
    //
    // Verify
    //
    //*************************************************************************
    Verify::Verify(Environment & environment,
                   Id id,
                   char const * parameters)
        : TaskBase(environment, id, Type::Synchronous)
    {
        auto command = TaskFactory::GetNextToken(parameters);
        if (command.compare("one") == 0)
        {
            m_isSingleQuery = true;
            m_isOutput = false;
            m_query = parameters;
        }
        else if (command.compare("log") == 0)
        {
            m_isSingleQuery = false;
            m_isOutput = false;
            m_query = TaskFactory::GetNextToken(parameters);
        }
        else if (command.compare("output") == 0)
        {
            m_isSingleQuery = false;
            m_isOutput = true;
            m_query = TaskFactory::GetNextToken(parameters);
        }
        else
        {
            RecoverableError error("Query expects \"one\" or \"log\".");
            throw error;
        }
    }

    // TODO: this should be somewhere else.
    std::unique_ptr<IMatchVerifier> VerifyOneQuery(
        Environment & environment,
        std::string query,
        bool runVerification)
    {
        static const size_t c_allocatorSize = 1ull << 16;
        Allocator allocator(c_allocatorSize);

        auto streamConfiguration = Factories::CreateStreamConfiguration();

        QueryParser parser(query.c_str(), *streamConfiguration, allocator);
        auto tree = parser.Parse();

        std::unique_ptr<IMatchVerifier> verifier =
            Factories::CreateMatchVerifier(query);

        if (tree == nullptr)
        {
            // std::cout << "Empty query." << std::endl;
        }
        else
        {
            // auto & environment = GetEnvironment();
            auto & cache = environment.GetIngestor().GetDocumentCache();
            auto & config = environment.GetConfiguration();
            TermMatchTreeEvaluator evaluator(config);

            size_t matchCount = 0;
            size_t documentCount = 0;

            if (runVerification)
            {
                for (auto entry : cache)
                {
                    ++documentCount;
                    bool matches = evaluator.Evaluate(*tree, entry.first);

                    if (matches)
                    {
                        ++matchCount;
                        //std::cout
                        //    << "  DocId(" << entry.second << ") "
                        //    << std::endl;

                        verifier->AddExpected(entry.second);
                    }
                }
            }

            // std::cout
            //     << matchCount << " match(es) out of "
            //     << documentCount << " documents."
            //     << std::endl;

            auto diagnosticStream = Factories::CreateDiagnosticStream(std::cout);
            // diagnosticStream->Enable("");

            QueryInstrumentation instrumentation;

            ResultsBuffer results(environment.GetSimpleIndex().GetIngestor().GetDocumentCount());

            Factories::RunQueryPlanner(*tree,
                                       environment.GetSimpleIndex(),
                                       allocator,
                                       *diagnosticStream,
                                       instrumentation,
                                       results);

            for (auto result : results)
            {
                DocumentHandle handle = Factories::CreateDocumentHandle(result.m_slice, result.m_index);
                verifier->AddObserved(handle.GetDocId());
            }

            verifier->Verify();
            //verifier->Print(std::cout);
        }
        return verifier;
    }

    void Verify::Execute()
    {
        if (m_isSingleQuery)
        {
            std::cout
                << "Processing query \""
                << m_query
                << "\"" << std::endl;
            auto verifier = VerifyOneQuery(GetEnvironment(), m_query, true);
            std::cout << "True positive count: "
                << verifier->GetTruePositiveCount()
                << std::endl
                << "False positive count: "
                << verifier->GetFalsePositiveCount()
                << std::endl
                << "False negative count: "
                << verifier->GetFalseNegativeCount()
                << std::endl;
            if (verifier->GetTruePositiveCount() > 0)
            {
                std::cout << "True positives: ";
                size_t counter = 0;
                for (const auto doc : verifier->GetTruePositives())
                {
                    if (counter != 0)
                    {
                        std::cout << ", ";
                    }
                    std::cout << doc;
                    ++counter;
                }
                std::cout << std::endl;
                std::cout << std::endl;
            }

            if (verifier->GetFalsePositiveCount() > 0)
            {
                std::cout << "False positives:" << std::endl;
                for (const auto doc : verifier->GetFalsePositives())
                {
                    std::cout << doc << ",";
                }
                std::cout << std::endl;
            }

            if (verifier->GetFalseNegativeCount() > 0)
            {
                std::cout << "False negatives:" << std::endl;
                for (const auto doc : verifier->GetFalseNegatives())
                {
                    std::cout << doc << ",";
                }
                std::cout << std::endl;

                throw RecoverableError("MatchVerifier: false negative detected.");
            }
        }
        else
        {
            std::cout
                << "Processing queries from log at \""
                << m_query
                << "\"" << std::endl;
            auto fileSystem = Factories::CreateFileSystem();  // TODO: Use environment file system
            auto queries = ReadLines(*fileSystem, m_query.c_str());

            // TODO: use FileManager.
            auto verificationOut = GetEnvironment().
                GetFileSystem().
                OpenForWrite("verificationOutput.csv");
            CsvTsv::CsvTableFormatter verificationFormatter(*verificationOut);
            CsvTsv::TableWriter writer(verificationFormatter);
            CsvTsv::OutputColumn<std::string>
                queryString("Query",
                            "Query text");
            CsvTsv::OutputColumn<uint64_t>
                docId("Document",
                      "ID of document.");
            CsvTsv::OutputColumn<uint64_t>
                type("Type",
                     "0: true positive. 1: false positive. 2: false negative. 3: unchecked result. TODO: fix this");

            writer.DefineColumn(queryString);
            writer.DefineColumn(docId);
            writer.DefineColumn(type);
            writer.WritePrologue();

            auto verificationSummary = GetEnvironment().
                GetFileSystem().
                OpenForWrite("verificationSummary.csv");
            CsvTsv::CsvTableFormatter summaryFormatter(*verificationSummary);
            CsvTsv::TableWriter summary(summaryFormatter);
            CsvTsv::OutputColumn<uint64_t>
                termPos("TermPos",
                        "Term position.");
            CsvTsv::OutputColumn<uint64_t>
                numTruePos("TruePositives",
                           "Number of true positives.");
            CsvTsv::OutputColumn<uint64_t>
                numFalsePos("FalsePositives",
                            "Number of false positives.");
            CsvTsv::OutputColumn<uint64_t>
                numFalseNeg("FalseNegatives",
                            "Number of true negatives.");
            CsvTsv::OutputColumn<double>
                falseRate("FalseRate",
                          "(Num false positives) / (Num total matches).");

            summary.DefineColumn(queryString);
            summary.DefineColumn(termPos);
            summary.DefineColumn(numTruePos);
            summary.DefineColumn(numFalsePos);
            summary.DefineColumn(numFalseNeg);
            summary.DefineColumn(falseRate);
            summary.WritePrologue();

            uint64_t position = 0;
            for (const auto & query : queries)
            {
                auto verifier = VerifyOneQuery(GetEnvironment(), query, !m_isOutput);
                queryString = verifier->GetQuery();

                if (!m_isOutput)
                {
                    std::vector<DocId> results = verifier->GetTruePositives();
                    numTruePos = results.size();
                    type = 0;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                    results = verifier->GetFalsePositives();
                    numFalsePos = results.size();
                    type = 1;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                    results = verifier->GetFalseNegatives();
                    numFalseNeg = results.size();
                    type = 2;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                    falseRate = static_cast<double>(numFalsePos) /
                        (static_cast<double>(numFalsePos) +
                         static_cast<double>(numTruePos));

                    summary.WriteDataRow();
                    ++position;
                    termPos = position;
                }
                else
                {
                    // TODO: fix this confusing setup. In m_isOutput mode, we
                    // never run the verifier and therefore never have
                    // "expected" results, which means that everything shows up
                    // as a false positive. This terminology conflict is because
                    // we added this mode after creating the verifier.
                    std::vector<DocId> results = verifier->GetFalsePositives();
                    type = 3;
                    for (const auto id : results)
                    {
                        docId = id;
                        writer.WriteDataRow();
                    }

                }
            }

            writer.WriteEpilogue();
            summary.WriteEpilogue();
        }
    }

    ICommand::Documentation Verify::GetDocumentation()
    {
        return Documentation(
            "verify",
            "Verifies the results of a single query against the document cache.",
            "verify (one <expression>) | (log <file>)\n"
            "  Verifies a single query or a list of queries\n"
            "  against the document cache.\n"
        );
    }
}
<|endoftext|>


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

#ifndef UDPSERVER_HPP_INCLUDED
#define UDPSERVER_HPP_INCLUDED

#include "NetComponent.hpp"
#include "Logger.hpp"
#include <string>
#include <vector>
#include <utility>
#include <thread>

/* Arbitrary datagram max buffer size */
#define PACKET_SIZE 65535

namespace Mach
{

/*
 * UDP server
 *
 * This server is able to listen on both IPv4 and IPv6 addresses and receives
 * datagrams using separate listening threads (on per socket).
 * Users of this class shall inherit from it and implement the
 * receiveBytes(...) method in order to instantiate a concrete server.
 * It uses a threaded model, so any implementation of UDPServer::receiveBytes
 * should be thought in a thread-safe way: using std::mutex for queuing
 * incoming messages into a common data structure might be a good idea,
 * for example.
 */
class UDPServer : public NetComponent
{
	private:
		/* Is the server currently listening ? */
		bool _listening;

		/* Socket vector <file descriptor , address information> */
		std::vector< std::pair< int, addrinfo > > _sockets;

		/* Currently running listener threads */
		std::vector< std::thread > _threads;

		/* Error & misc information logger */
		Logger _log;

		/* No copy, no assignation */
		UDPServer(UDPServer const &);
		UDPServer & operator = (UDPServer const &);

	protected:
		/* Try binding to the given addrinfo (or any if nullptr is given) */
		void bindTo(addrinfo const *);

		/* Listen on the given socket as long as it is valid */
		void listener(std::pair< int, addrinfo >);

		/* Send some data to destination using the given socket */
		void sendBytes(uint8_t const *, size_t, sockaddr const *,
				int const);

		/* Handle an incoming datagram */
		virtual void receiveBytes(uint8_t const *, size_t const,
				sockaddr_storage const *, int const) = 0;

	public:
		/* Constructor & destructor */
		UDPServer(unsigned short const port,
				std::string const logPath = "UDPServer.log",
				Priority const prio = LOG_ERROR);
		virtual ~UDPServer();

		/* Start listening on all bound sockets */
		void startListening();

		/* Close bound sockets & stop listening */
		void stopListening();
};

}

#endif // UDPSERVER_HPP_INCLUDED
<commit_msg>Use of C++11 syntax for deleted methods<commit_after>/*
 * Copyright (c) 2016 Julien "Derjik" Laurent <julien.laurent@engineer.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef UDPSERVER_HPP_INCLUDED
#define UDPSERVER_HPP_INCLUDED

#include "NetComponent.hpp"
#include "Logger.hpp"
#include <string>
#include <vector>
#include <utility>
#include <thread>

/* Arbitrary datagram max buffer size */
#define PACKET_SIZE 65535

namespace Mach
{

/*
 * UDP server
 *
 * This server is able to listen on both IPv4 and IPv6 addresses and receives
 * datagrams using separate listening threads (on per socket).
 * Users of this class shall inherit from it and implement the
 * receiveBytes(...) method in order to instantiate a concrete server.
 * It uses a threaded model, so any implementation of UDPServer::receiveBytes
 * should be thought in a thread-safe way: using std::mutex for queuing
 * incoming messages into a common data structure might be a good idea,
 * for example.
 */
class UDPServer : public NetComponent
{
	private:
		/* Is the server currently listening ? */
		bool _listening;

		/* Socket vector <file descriptor , address information> */
		std::vector< std::pair< int, addrinfo > > _sockets;

		/* Currently running listener threads */
		std::vector< std::thread > _threads;

		/* Error & misc information logger */
		Logger _log;

	protected:
		/* Try binding to the given addrinfo (or any if nullptr is given) */
		void bindTo(addrinfo const *);

		/* Listen on the given socket as long as it is valid */
		void listener(std::pair< int, addrinfo >);

		/* Send some data to destination using the given socket */
		void sendBytes(uint8_t const *, size_t, sockaddr const *,
				int const);

		/* Handle an incoming datagram */
		virtual void receiveBytes(uint8_t const *, size_t const,
				sockaddr_storage const *, int const) = 0;

	public:
		/* Constructor & destructor */
		UDPServer(unsigned short const port,
				std::string const logPath = "UDPServer.log",
				Priority const prio = LOG_ERROR);
		virtual ~UDPServer();

		/* No copy, no assignation */
		UDPServer(UDPServer const &) = delete;
		UDPServer & operator = (UDPServer const &) = delete;

		/* Start listening on all bound sockets */
		void startListening();

		/* Close bound sockets & stop listening */
		void stopListening();
};

}

#endif // UDPSERVER_HPP_INCLUDED
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "util/tmp.hpp"

namespace dll {

namespace detail {

/*!
 * \brief Helper traits indicate if the set contains dynamic layers
 */
template <typename... Layers>
struct is_dynamic : cpp::or_u<layer_traits<Layers>::is_dynamic()...> {};

/*!
 * \brief Helper traits indicate if the set contains convolutional layers
 */
template <typename... Layers>
struct is_convolutional : cpp::or_u<layer_traits<Layers>::is_convolutional_layer()...> {};

template <typename... Layers>
struct is_denoising : cpp::and_u<layer_traits<Layers>::is_dense_rbm_layer()...> {};

template <typename Layer, typename Enable = void>
struct has_shuffle_helper;

template <typename Layer>
struct has_shuffle_helper <Layer, std::enable_if_t<layer_traits<Layer>::is_rbm_layer()>> {
    static constexpr bool value = rbm_layer_traits<Layer>::has_shuffle();
};

template <typename Layer>
struct has_shuffle_helper <Layer, std::enable_if_t<!layer_traits<Layer>::is_rbm_layer()>> {
    static constexpr bool value = false;
};

/*!
 * \brief Helper traits indicate if the set contains shuffle layers
 */
template <typename... Layers>
struct has_shuffle_layer : cpp::or_u<has_shuffle_helper<Layers>::value...> {};

// TODO validate_layer_pair should be made more robust when
// transform layer are present between layers

template <typename L1, typename L2, typename Enable = void>
struct validate_layer_pair;

template <typename L1, typename L2>
struct validate_layer_pair<L1, L2, std::enable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>>
    : std::true_type {};

template <typename L1, typename L2>
struct validate_layer_pair<L1, L2, cpp::disable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>> : cpp::bool_constant<L1::output_size() == L2::input_size()> {};

template <typename... Layers>
struct validate_layers_impl;

template <typename Layer>
struct validate_layers_impl<Layer> : std::true_type {};

template <typename L1, typename L2, typename... Layers>
struct validate_layers_impl<L1, L2, Layers...> : cpp::bool_constant_c<
                                                     cpp::and_u<
                                                         validate_layer_pair<L1, L2>::value,
                                                         validate_layers_impl<L2, Layers...>::value>> {};

//Note: It is not possible to add a template parameter with default value (SFINAE) on a variadic struct
//therefore, implementing the traits as function is nicer than nested structures

template <typename... Layers, cpp_enable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid() {
    return true;
}

template <typename... Layers, cpp_disable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid() {
    return validate_layers_impl<Layers...>();
}

template <typename... Layers>
struct validate_label_layers;

template <typename Layer>
struct validate_label_layers<Layer> : std::true_type {};

template <typename L1, typename L2, typename... Layers>
struct validate_label_layers<L1, L2, Layers...> : cpp::bool_constant_c<
                                                      cpp::and_u<
                                                          layer_traits<L1>::output_size() <= layer_traits<L2>::input_size(),
                                                          validate_label_layers<L2, Layers...>::value>> {};

} // end of namespace detail

namespace detail {

template <size_t I, typename T>
struct layers_leaf {
    T value;

    T& get() noexcept {
        return value;
    }

    const T& get() const noexcept {
        return value;
    }
};

template <typename Indices, typename... Layers>
struct layers_impl;

template <size_t... I, typename... Layers>
struct layers_impl<std::index_sequence<I...>, Layers...> : layers_leaf<I, Layers>... {
};

template <bool Labels, typename... Layers>
struct layers;

template <typename... Layers>
struct layers <false, Layers...> {
    static constexpr size_t size = sizeof...(Layers);

    static constexpr bool is_dynamic        = detail::is_dynamic<Layers...>();
    static constexpr bool is_convolutional  = detail::is_convolutional<Layers...>();
    static constexpr bool is_denoising      = detail::is_denoising<Layers...>();
    static constexpr bool has_shuffle_layer = detail::has_shuffle_layer<Layers...>();

    static_assert(size > 0, "A network must have at least 1 layer");
    static_assert(detail::are_layers_valid<Layers...>(), "The inner sizes of RBM must correspond");

    using base_t      = layers_impl<std::make_index_sequence<size>, Layers...>;
    using layers_list = cpp::type_list<Layers...>;

    base_t base;
};

template <typename... Layers>
struct layers <true, Layers...> {
    static constexpr size_t size = sizeof...(Layers);

    static constexpr bool is_dynamic        = false;
    static constexpr bool is_convolutional  = false;
    static constexpr bool is_denoising      = false;
    static constexpr bool has_shuffle_layer = detail::has_shuffle_layer<Layers...>();

    static_assert(size > 0, "A network must have at least 1 layer");
    static_assert(detail::validate_label_layers<Layers...>::value, "The inner sizes of RBM must correspond");
    static_assert(!detail::is_dynamic<Layers...>(), "dbn_label_layers should not be used with dynamic RBMs");

    using base_t      = layers_impl<std::make_index_sequence<size>, Layers...>;
    using layers_list = cpp::type_list<Layers...>;

    base_t base;
};

//Note: Maybe simplify further removing the type_list

template <size_t I, typename T>
struct layer_type;

template <size_t I>
struct layer_type<I, cpp::type_list<>> {
    static_assert(I == 0, "index out of range");
    static_assert(I != 0, "index out of range");
};

template <typename Head, typename... T>
struct layer_type<0, cpp::type_list<Head, T...>> {
    using type = Head;
};

template <size_t I, typename Head, typename... T>
struct layer_type<I, cpp::type_list<Head, T...>> {
    using type = typename layer_type<I - 1, cpp::type_list<T...>>::type;
};

template <size_t I, bool Labels, typename... Layers>
struct layer_type<I, layers<Labels, Layers...>> {
    using type = typename layer_type<I, cpp::type_list<Layers...>>::type;
};

template <size_t I, typename Layers>
using layer_type_t = typename layer_type<I, Layers>::type;

/*!
 * \brief Return the Ith layer in the given layer set
 * \param layers The layers holder
 * \tparam I The layer to get
 * \return a reference to the Ith layer in the given layer set
 */
template <size_t I, typename Layers>
layer_type_t<I, Layers>& layer_get(Layers& layers) {
    return static_cast<layers_leaf<I, layer_type_t<I, Layers>>&>(layers.base).get();
}

/*!
 * \brief Return the Ith layer in the given layer set
 * \param layers The layers holder
 * \tparam I The layer to get
 * \return a reference to the Ith layer in the given layer set
 */
template <size_t I, typename Layers>
const layer_type_t<I, Layers>& layer_get(const Layers& layers) {
    return static_cast<const layers_leaf<I, layer_type_t<I, Layers>>&>(layers.base).get();
}

template <typename DBN, typename Functor, size_t... I>
void for_each_layer_type_sub(Functor&& functor, const std::index_sequence<I...>& /* i */) {
    int wormhole[] = {(functor(static_cast<typename DBN::template layer_type<I>*>(nullptr)), 0)...};
    cpp_unused(wormhole);
}

template <typename DBN, typename Functor>
void for_each_layer_type(Functor&& functor) {
    for_each_layer_type_sub<DBN>(functor, std::make_index_sequence<DBN::layers>());
}

} //end of namespace detail

/*!
 * \brief Holder for the layers of a DBN
 */
template <typename... Layers>
using dbn_layers = detail::layers<false, Layers...>;

/*!
 * \brief Holder for the layers of a DBN, training with labels + RBM in last layer
 */
template <typename... Layers>
using dbn_label_layers = detail::layers<false, Layers...>;

} //end of namespace dll
<commit_msg>Fix label layers validation<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "util/tmp.hpp"

namespace dll {

namespace detail {

/*!
 * \brief Helper traits indicate if the set contains dynamic layers
 */
template <typename... Layers>
struct is_dynamic : cpp::or_u<layer_traits<Layers>::is_dynamic()...> {};

/*!
 * \brief Helper traits indicate if the set contains convolutional layers
 */
template <typename... Layers>
struct is_convolutional : cpp::or_u<layer_traits<Layers>::is_convolutional_layer()...> {};

template <typename... Layers>
struct is_denoising : cpp::and_u<layer_traits<Layers>::is_dense_rbm_layer()...> {};

template <typename Layer, typename Enable = void>
struct has_shuffle_helper;

template <typename Layer>
struct has_shuffle_helper <Layer, std::enable_if_t<layer_traits<Layer>::is_rbm_layer()>> {
    static constexpr bool value = rbm_layer_traits<Layer>::has_shuffle();
};

template <typename Layer>
struct has_shuffle_helper <Layer, std::enable_if_t<!layer_traits<Layer>::is_rbm_layer()>> {
    static constexpr bool value = false;
};

/*!
 * \brief Helper traits indicate if the set contains shuffle layers
 */
template <typename... Layers>
struct has_shuffle_layer : cpp::or_u<has_shuffle_helper<Layers>::value...> {};

// TODO validate_layer_pair should be made more robust when
// transform layer are present between layers

template <typename L1, typename L2, typename Enable = void>
struct validate_layer_pair;

template <typename L1, typename L2>
struct validate_layer_pair<L1, L2, std::enable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>>
    : std::true_type {};

template <typename L1, typename L2>
struct validate_layer_pair<L1, L2, cpp::disable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>> : cpp::bool_constant<L1::output_size() == L2::input_size()> {};

template <typename... Layers>
struct validate_layers_impl;

template <typename Layer>
struct validate_layers_impl<Layer> : std::true_type {};

template <typename L1, typename L2, typename... Layers>
struct validate_layers_impl<L1, L2, Layers...> : cpp::bool_constant_c<
                                                     cpp::and_u<
                                                         validate_layer_pair<L1, L2>::value,
                                                         validate_layers_impl<L2, Layers...>::value>> {};

//Note: It is not possible to add a template parameter with default value (SFINAE) on a variadic struct
//therefore, implementing the traits as function is nicer than nested structures

template <typename... Layers, cpp_enable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid() {
    return true;
}

template <typename... Layers, cpp_disable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid() {
    return validate_layers_impl<Layers...>();
}

template <typename... Layers>
struct validate_label_layers;

template <typename Layer>
struct validate_label_layers<Layer> : std::true_type {};

template <typename L1, typename L2, typename... Layers>
struct validate_label_layers<L1, L2, Layers...> : cpp::bool_constant_c<
                                                      cpp::and_u<
                                                          L1::output_size() <= L2::input_size(),
                                                          validate_label_layers<L2, Layers...>::value>> {};

} // end of namespace detail

namespace detail {

template <size_t I, typename T>
struct layers_leaf {
    T value;

    T& get() noexcept {
        return value;
    }

    const T& get() const noexcept {
        return value;
    }
};

template <typename Indices, typename... Layers>
struct layers_impl;

template <size_t... I, typename... Layers>
struct layers_impl<std::index_sequence<I...>, Layers...> : layers_leaf<I, Layers>... {
};

template <bool Labels, typename... Layers>
struct layers;

template <typename... Layers>
struct layers <false, Layers...> {
    static constexpr size_t size = sizeof...(Layers);

    static constexpr bool is_dynamic        = detail::is_dynamic<Layers...>();
    static constexpr bool is_convolutional  = detail::is_convolutional<Layers...>();
    static constexpr bool is_denoising      = detail::is_denoising<Layers...>();
    static constexpr bool has_shuffle_layer = detail::has_shuffle_layer<Layers...>();

    static_assert(size > 0, "A network must have at least 1 layer");
    static_assert(detail::are_layers_valid<Layers...>(), "The inner sizes of RBM must correspond");

    using base_t      = layers_impl<std::make_index_sequence<size>, Layers...>;
    using layers_list = cpp::type_list<Layers...>;

    base_t base;
};

template <typename... Layers>
struct layers <true, Layers...> {
    static constexpr size_t size = sizeof...(Layers);

    static constexpr bool is_dynamic        = false;
    static constexpr bool is_convolutional  = false;
    static constexpr bool is_denoising      = false;
    static constexpr bool has_shuffle_layer = detail::has_shuffle_layer<Layers...>();

    static_assert(size > 0, "A network must have at least 1 layer");
    static_assert(detail::validate_label_layers<Layers...>::value, "The inner sizes of RBM must correspond");
    static_assert(!detail::is_dynamic<Layers...>(), "dbn_label_layers should not be used with dynamic RBMs");

    using base_t      = layers_impl<std::make_index_sequence<size>, Layers...>;
    using layers_list = cpp::type_list<Layers...>;

    base_t base;
};

//Note: Maybe simplify further removing the type_list

template <size_t I, typename T>
struct layer_type;

template <size_t I>
struct layer_type<I, cpp::type_list<>> {
    static_assert(I == 0, "index out of range");
    static_assert(I != 0, "index out of range");
};

template <typename Head, typename... T>
struct layer_type<0, cpp::type_list<Head, T...>> {
    using type = Head;
};

template <size_t I, typename Head, typename... T>
struct layer_type<I, cpp::type_list<Head, T...>> {
    using type = typename layer_type<I - 1, cpp::type_list<T...>>::type;
};

template <size_t I, bool Labels, typename... Layers>
struct layer_type<I, layers<Labels, Layers...>> {
    using type = typename layer_type<I, cpp::type_list<Layers...>>::type;
};

template <size_t I, typename Layers>
using layer_type_t = typename layer_type<I, Layers>::type;

/*!
 * \brief Return the Ith layer in the given layer set
 * \param layers The layers holder
 * \tparam I The layer to get
 * \return a reference to the Ith layer in the given layer set
 */
template <size_t I, typename Layers>
layer_type_t<I, Layers>& layer_get(Layers& layers) {
    return static_cast<layers_leaf<I, layer_type_t<I, Layers>>&>(layers.base).get();
}

/*!
 * \brief Return the Ith layer in the given layer set
 * \param layers The layers holder
 * \tparam I The layer to get
 * \return a reference to the Ith layer in the given layer set
 */
template <size_t I, typename Layers>
const layer_type_t<I, Layers>& layer_get(const Layers& layers) {
    return static_cast<const layers_leaf<I, layer_type_t<I, Layers>>&>(layers.base).get();
}

template <typename DBN, typename Functor, size_t... I>
void for_each_layer_type_sub(Functor&& functor, const std::index_sequence<I...>& /* i */) {
    int wormhole[] = {(functor(static_cast<typename DBN::template layer_type<I>*>(nullptr)), 0)...};
    cpp_unused(wormhole);
}

template <typename DBN, typename Functor>
void for_each_layer_type(Functor&& functor) {
    for_each_layer_type_sub<DBN>(functor, std::make_index_sequence<DBN::layers>());
}

} //end of namespace detail

/*!
 * \brief Holder for the layers of a DBN
 */
template <typename... Layers>
using dbn_layers = detail::layers<false, Layers...>;

/*!
 * \brief Holder for the layers of a DBN, training with labels + RBM in last layer
 */
template <typename... Layers>
using dbn_label_layers = detail::layers<true, Layers...>;

} //end of namespace dll
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file random.hpp
 * \date 2014
 * \author Jan Issac (jan.issac@gmail.com)
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 */

#ifndef FL__UTIL__RANDOM_HPP
#define FL__UTIL__RANDOM_HPP

#include <ctime>
#include <random>

/**
 * \brief global seed
 *
 * \ingroup random
 */
#ifdef USE_RANDOM_SEED
    #define RANDOM_SEED (unsigned int) std::time(0)
#else
    #define RANDOM_SEED 1
#endif

namespace fl
{

/**
 * Mersenne Twister specialization mt11213b \cite matsumoto1998mersenne
 * \ingroup random
 *
 *
 * mt11213b is slightly faster than mt19937
 */
typedef std::mersenne_twister_engine<
                uint32_t,
                32, 351, 175, 19,
                0xccab8ee7, 11,
                0xffffffff, 7,
                0x31b6ab00, 15,
                0xffe50000, 17,
                1812433253 > mt11213b;

/**
 * \return A seed. If USE_RANDOM_SEED was set true the seed is set to the
 * current time, otherwise, the seed will be 1.
 *
 * \ingroup random
 */
inline unsigned int seed()
{
#ifdef USE_RANDOM_SEED
    return (unsigned int) std::time(0);
#else
    return 1;
#endif
}

}

#endif
<commit_msg>updated seed() generating function<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file random.hpp
 * \date 2014
 * \author Jan Issac (jan.issac@gmail.com)
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 */

#ifndef FL__UTIL__RANDOM_HPP
#define FL__UTIL__RANDOM_HPP

#include <ctime>
#include <chrono>
#include <random>
#include <iostream>
#include <iomanip>
/**
 * \brief global seed
 *
 * \ingroup random
 */
#ifdef USE_RANDOM_SEED
    #define RANDOM_SEED (unsigned int) std::time(0)
#else
    #define RANDOM_SEED 1
#endif

namespace fl
{

/**
 * Mersenne Twister specialization mt11213b \cite matsumoto1998mersenne
 * \ingroup random
 *
 *
 * mt11213b is slightly faster than mt19937
 */
typedef std::mersenne_twister_engine<
                uint32_t,
                32, 351, 175, 19,
                0xccab8ee7, 11,
                0xffffffff, 7,
                0x31b6ab00, 15,
                0xffe50000, 17,
                1812433253 > mt11213b;

/**
 * \return A seed. If USE_RANDOM_SEED was set true the seed is set to the
 * current time, otherwise, the seed will be 1.
 *
 * \ingroup random
 */

static unsigned int seed_inc = 0;
inline unsigned int seed()
{
    return std::time(0) + (++seed_inc);

//#ifdef USE_RANDOM_SEED
//    return (unsigned int) std::time(0);
//#else
//    return 1;
//#endif
}

}

#endif
<|endoftext|>


<commit_before>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_RSS_HPP_INCLUDED
#define TORRENT_RSS_HPP_INCLUDED

#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/size_type.hpp"

#include <boost/enable_shared_from_this.hpp>
#include <string>

namespace libtorrent
{
	namespace aux
	{ struct session_impl; }

	struct feed_item
	{
		feed_item(): size(-1) {}
		std::string url;
		std::string uuid;
		std::string title;
		std::string description;
		std::string comment;
		std::string category;
		size_type size;
		torrent_handle handle;
		sha1_hash info_hash;
	};

#ifndef BOOST_NO_EXCEPTIONS
	torrent_handle add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p);
#endif

	torrent_handle add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p, error_code& ec);

	// the feed_settings object is all the information
	// and configuration for a specific feed. All of
	// these settings can be changed by the user
	// after adding the feed
	struct feed_settings
	{
		feed_settings()
			: auto_download(true)
			, default_ttl(30)
		{}

   	std::string url;

		bool auto_download;

		// in minutes
		int default_ttl;

		// used when adding torrents
		add_torrent_params add_args;
	};

	struct feed_status
	{
		feed_status(): last_update(0), next_update(0)
			, updating(false), ttl(0) {}
		std::string url;
		std::string title;
		std::string description;
		time_t last_update;
		int next_update;
		bool updating;
		std::vector<feed_item> items;
		error_code error;
		int ttl;
	};

	struct feed;

	struct feed_handle
	{
		feed_handle() {}
		void update_feed();
		feed_status get_feed_status() const;
		void set_settings(feed_settings const& s);
		feed_settings settings() const;
	private:
		friend struct aux::session_impl;
		friend struct feed;
		feed_handle(boost::weak_ptr<feed> const& p);
		boost::weak_ptr<feed> m_feed_ptr;
	};

	struct feed_state;
	class http_parser;

	boost::shared_ptr<feed> new_feed(aux::session_impl& ses, feed_settings const& sett);

	// this is the internal object holding all state about an
	// RSS feed. All user interaction with this object
	// goes through the feed_handle, which makes sure all calls
	// are posted to the network thread
	struct feed : boost::enable_shared_from_this<feed>
	{
		friend void parse_feed(feed_state& f, int token, char const* name, char const* val);

		feed(aux::session_impl& ses, feed_settings const& feed);

		void on_feed(error_code const& ec, http_parser const& parser
			, char const* data, int size);

		void update_feed();

		aux::session_impl& session() const { return m_ses; }

		void set_settings(feed_settings const& s);
		void get_settings(feed_settings* s) const;
   	void get_feed_status(feed_status* ret) const;

		int next_update(time_t now) const;

		void load_state(lazy_entry const& rd);
		void save_state(entry& rd) const;

//	private:

		feed_handle my_handle();

		error_code m_error;
		std::vector<feed_item> m_items;
		std::string m_title;
   	std::string m_description;
		time_t m_last_attempt;
   	time_t m_last_update;
		// refresh rate of this feed in minutes
		int m_ttl;
		// true while waiting for the server to respond
		bool m_updating;
		feed_settings m_settings;

		aux::session_impl& m_ses;
	};

};

#endif

<commit_msg>add export macros<commit_after>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_RSS_HPP_INCLUDED
#define TORRENT_RSS_HPP_INCLUDED

#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/size_type.hpp"

#include <boost/enable_shared_from_this.hpp>
#include <string>

namespace libtorrent
{
	namespace aux
	{ struct session_impl; }

	struct feed_item
	{
		feed_item(): size(-1) {}
		std::string url;
		std::string uuid;
		std::string title;
		std::string description;
		std::string comment;
		std::string category;
		size_type size;
		torrent_handle handle;
		sha1_hash info_hash;
	};

#ifndef BOOST_NO_EXCEPTIONS
	torrent_handle TORRENT_EXPORT add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p);
#endif

	torrent_handle TORRENT_EXPORT add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p, error_code& ec);

	// the feed_settings object is all the information
	// and configuration for a specific feed. All of
	// these settings can be changed by the user
	// after adding the feed
	struct feed_settings
	{
		feed_settings()
			: auto_download(true)
			, default_ttl(30)
		{}

   	std::string url;

		bool auto_download;

		// in minutes
		int default_ttl;

		// used when adding torrents
		add_torrent_params add_args;
	};

	struct feed_status
	{
		feed_status(): last_update(0), next_update(0)
			, updating(false), ttl(0) {}
		std::string url;
		std::string title;
		std::string description;
		time_t last_update;
		int next_update;
		bool updating;
		std::vector<feed_item> items;
		error_code error;
		int ttl;
	};

	struct feed;

	struct TORRENT_EXPORT feed_handle
	{
		feed_handle() {}
		void update_feed();
		feed_status get_feed_status() const;
		void set_settings(feed_settings const& s);
		feed_settings settings() const;
	private:
		friend struct aux::session_impl;
		friend struct feed;
		feed_handle(boost::weak_ptr<feed> const& p);
		boost::weak_ptr<feed> m_feed_ptr;
	};

	struct feed_state;
	class http_parser;

	boost::shared_ptr<feed> new_feed(aux::session_impl& ses, feed_settings const& sett);

	// this is the internal object holding all state about an
	// RSS feed. All user interaction with this object
	// goes through the feed_handle, which makes sure all calls
	// are posted to the network thread
	struct TORRENT_EXPORT feed : boost::enable_shared_from_this<feed>
	{
		friend void parse_feed(feed_state& f, int token, char const* name, char const* val);

		feed(aux::session_impl& ses, feed_settings const& feed);

		void on_feed(error_code const& ec, http_parser const& parser
			, char const* data, int size);

		void update_feed();

		aux::session_impl& session() const { return m_ses; }

		void set_settings(feed_settings const& s);
		void get_settings(feed_settings* s) const;
   	void get_feed_status(feed_status* ret) const;

		int next_update(time_t now) const;

		void load_state(lazy_entry const& rd);
		void save_state(entry& rd) const;

//	private:

		feed_handle my_handle();

		error_code m_error;
		std::vector<feed_item> m_items;
		std::string m_title;
   	std::string m_description;
		time_t m_last_attempt;
   	time_t m_last_update;
		// refresh rate of this feed in minutes
		int m_ttl;
		// true while waiting for the server to respond
		bool m_updating;
		feed_settings m_settings;

		aux::session_impl& m_ses;
	};

};

#endif

<|endoftext|>


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

#ifndef MAPNIK_VERSION_HPP
#define MAPNIK_VERSION_HPP

#define MAPNIK_VERSION 800

#endif //MAPNIK_VERSION_HPP

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

#ifndef MAPNIK_VERSION_HPP
#define MAPNIK_VERSION_HPP

#define MAPNIK_VERSION 200000

#endif //MAPNIK_VERSION_HPP

<|endoftext|>


<commit_before>//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2008-2010 FURUHASHI Sadayuki
//
//    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.
//
#ifndef MSGPACK_OBJECT_HPP
#define MSGPACK_OBJECT_HPP

#include "object.h"
#include "pack.hpp"
#include "zone.hpp"
#include <string.h>
#include <stdexcept>
#include <typeinfo>
#include <limits>
#include <ostream>

namespace msgpack {

class type_error : public std::bad_cast { };

namespace type {
    enum object_type {
        NIL                 = MSGPACK_OBJECT_NIL,
        BOOLEAN             = MSGPACK_OBJECT_BOOLEAN,
        POSITIVE_INTEGER    = MSGPACK_OBJECT_POSITIVE_INTEGER,
        NEGATIVE_INTEGER    = MSGPACK_OBJECT_NEGATIVE_INTEGER,
        DOUBLE              = MSGPACK_OBJECT_DOUBLE,
        STR                 = MSGPACK_OBJECT_STR,
        BIN                 = MSGPACK_OBJECT_BIN,
        ARRAY               = MSGPACK_OBJECT_ARRAY,
        MAP                 = MSGPACK_OBJECT_MAP
    };
}

struct object;
struct object_kv;

struct object_array {
    uint32_t size;
    object* ptr;
};

struct object_map {
    uint32_t size;
    object_kv* ptr;
};

struct object_str {
    uint32_t size;
    const char* ptr;
};

struct object_bin {
    uint32_t size;
    const char* ptr;
};

struct object {
    union union_type {
        bool boolean;
        uint64_t u64;
        int64_t  i64;
        double   dec;
        object_array array;
        object_map map;
        object_str str;
        object_bin bin;
    };

    type::object_type type;
    union_type via;

    bool is_nil() const { return type == type::NIL; }

    template <typename T>
    T as() const;

    template <typename T>
    void convert(T& v) const;
    template <typename T>
    void convert(T* v) const;

    object();

    object(msgpack_object o);

    template <typename T>
    explicit object(const T& v);

    template <typename T>
    object(const T& v, zone* z);

    template <typename T>
    object& operator=(const T& v);

    operator msgpack_object() const;

    struct with_zone;

private:
    struct implicit_type;

public:
    implicit_type convert() const;
};

struct object_kv {
    object key;
    object val;
};

struct object::with_zone : object {
    with_zone(msgpack::zone* zone) : zone(zone) { }
    msgpack::zone* zone;
private:
    with_zone();
};

struct object::implicit_type {
    implicit_type(object const& o) : obj(o) { }
    ~implicit_type() { }

    template <typename T>
    operator T() { return obj.as<T>(); }

private:
    object const& obj;
};

// obsolete
template <typename Type>
class define : public Type {
public:
    typedef Type msgpack_type;
    typedef define<Type> define_type;

    define() {}
    define(const msgpack_type& v) : msgpack_type(v) {}

    template <typename Packer>
    void msgpack_pack(Packer& o) const
    {
        o << static_cast<const msgpack_type&>(*this);
    }

    void msgpack_unpack(object const& o)
    {
        o >> static_cast<msgpack_type&>(*this);
    }
};

template <typename Stream>
template <typename T>
inline packer<Stream>& packer<Stream>::pack(const T& v)
{
    *this << v;
    return *this;
}

inline object& operator>> (object const& o, object& v)
{
    v = o;
    return v;
}

// convert operator
template <typename T>
inline T& operator>> (object const& o, T& v)
{
    v.msgpack_unpack(o.convert());
    return v;
}

namespace detail {
template <typename Stream, typename T>
struct packer_serializer {
    static packer<Stream>& pack(packer<Stream>& o, const T& v) {
        v.msgpack_pack(o);
        return o;
    }
};
}

// serialize operator
template <typename Stream, typename T>
inline packer<Stream>& operator<< (packer<Stream>& o, const T& v)
{
    return detail::packer_serializer<Stream, T>::pack(o, v);
}

// deconvert operator
template <typename T>
inline void operator<< (object::with_zone& o, const T& v)
{
    v.msgpack_object(static_cast<object*>(&o), o.zone);
}

inline bool operator==(const object& x, const object& y)
{
    if(x.type != y.type) { return false; }

    switch(x.type) {
    case type::NIL:
        return true;

    case type::BOOLEAN:
        return x.via.boolean == y.via.boolean;

    case type::POSITIVE_INTEGER:
        return x.via.u64 == y.via.u64;

    case type::NEGATIVE_INTEGER:
        return x.via.i64 == y.via.i64;

    case type::DOUBLE:
        return x.via.dec == y.via.dec;

    case type::STR:
        return x.via.str.size == y.via.str.size &&
            memcmp(x.via.str.ptr, y.via.str.ptr, x.via.str.size) == 0;

    case type::BIN:
        return x.via.bin.size == y.via.bin.size &&
            memcmp(x.via.bin.ptr, y.via.bin.ptr, x.via.bin.size) == 0;

    case type::ARRAY:
        if(x.via.array.size != y.via.array.size) {
            return false;
        } else if(x.via.array.size == 0) {
            return true;
        } else {
            object* px = x.via.array.ptr;
            object* const pxend = x.via.array.ptr + x.via.array.size;
            object* py = y.via.array.ptr;
            do {
                if(!(*px == *py)) {
                    return false;
                }
                ++px;
                ++py;
            } while(px < pxend);
            return true;
        }

    case type::MAP:
        if(x.via.map.size != y.via.map.size) {
            return false;
        } else if(x.via.map.size == 0) {
            return true;
        } else {
            object_kv* px = x.via.map.ptr;
            object_kv* const pxend = x.via.map.ptr + x.via.map.size;
            object_kv* py = y.via.map.ptr;
            do {
                if(!(px->key == py->key) || !(px->val == py->val)) {
                    return false;
                }
                ++px;
                ++py;
            } while(px < pxend);
            return true;
        }

    default:
        return false;
    }
}

template <typename T>
inline bool operator==(const object& x, const T& y)
try {
    return x == object(y);
} catch (msgpack::type_error&) {
    return false;
}

inline bool operator!=(const object& x, const object& y)
{ return !(x == y); }

template <typename T>
inline bool operator==(const T& y, const object x)
{ return x == y; }

template <typename T>
inline bool operator!=(const object& x, const T& y)
{ return !(x == y); }

template <typename T>
inline bool operator!=(const T& y, const object& x)
{ return x != y; }

inline object::implicit_type object::convert() const
{
    return implicit_type(*this);
}

template <typename T>
inline void object::convert(T& v) const
{
    *this >> v;
}

template <typename T>
inline void object::convert(T* v) const
{
    convert(*v);
}

template <typename T>
inline T object::as() const
{
    T v;
    convert(v);
    return v;
}

inline object::object()
{
    type = type::NIL;
}

template <typename T>
inline object::object(const T& v)
{
    *this << v;
}

template <typename T>
inline object& object::operator=(const T& v)
{
    *this = object(v);
    return *this;
}

template <typename T>
object::object(const T& v, zone* z)
{
    with_zone oz(z);
    oz << v;
    type = oz.type;
    via = oz.via;
}

inline object::object(msgpack_object o)
{
    // FIXME beter way?
    ::memcpy(this, &o, sizeof(o));
}

inline void operator<< (object& o, msgpack_object v)
{
    // FIXME beter way?
    ::memcpy(&o, &v, sizeof(v));
}

inline object::operator msgpack_object() const
{
    // FIXME beter way?
    msgpack_object obj;
    ::memcpy(&obj, this, sizeof(obj));
    return obj;
}

// obsolete
template <typename T>
inline void convert(T& v, object const& o)
{
    o.convert(v);
}

// obsolete
template <typename Stream, typename T>
inline void pack(packer<Stream>& o, const T& v)
{
    o.pack(v);
}

// obsolete
template <typename Stream, typename T>
inline void pack_copy(packer<Stream>& o, T v)
{
    pack(o, v);
}

template <typename Stream>
packer<Stream>& operator<< (packer<Stream>& o, const object& v)
{
    switch(v.type) {
    case type::NIL:
        o.pack_nil();
        return o;

    case type::BOOLEAN:
        if(v.via.boolean) {
            o.pack_true();
        } else {
            o.pack_false();
        }
        return o;

    case type::POSITIVE_INTEGER:
        o.pack_uint64(v.via.u64);
        return o;

    case type::NEGATIVE_INTEGER:
        o.pack_int64(v.via.i64);
        return o;

    case type::DOUBLE:
        o.pack_double(v.via.dec);
        return o;

    case type::STR:
        o.pack_str(v.via.str.size);
        o.pack_str_body(v.via.str.ptr, v.via.str.size);
        return o;

    case type::BIN:
        o.pack_bin(v.via.bin.size);
        o.pack_bin_body(v.via.bin.ptr, v.via.bin.size);
        return o;

    case type::ARRAY:
        o.pack_array(v.via.array.size);
        for(object* p(v.via.array.ptr),
                * const pend(v.via.array.ptr + v.via.array.size);
                p < pend; ++p) {
            o << *p;
        }
        return o;

    case type::MAP:
        o.pack_map(v.via.map.size);
        for(object_kv* p(v.via.map.ptr),
                * const pend(v.via.map.ptr + v.via.map.size);
                p < pend; ++p) {
            o << p->key;
            o << p->val;
        }
        return o;

    default:
        throw type_error();
    }
}

std::ostream& operator<< (std::ostream& s, const object& o)
{
    switch(o.type) {
    case type::NIL:
        s << "nil";
        break;

    case type::BOOLEAN:
        s << (o.via.boolean ? "true" : "false");
        break;

    case type::POSITIVE_INTEGER:
        s << o.via.u64;
        break;

    case type::NEGATIVE_INTEGER:
        s << o.via.i64;
        break;

    case type::DOUBLE:
        s << o.via.dec;
        break;

    case type::STR:
        (s << '"').write(o.via.str.ptr, o.via.str.size) << '"';
        break;

    case type::BIN:
        (s << '"').write(o.via.bin.ptr, o.via.bin.size) << '"';
        break;

    case type::ARRAY:
        s << "[";
        if(o.via.array.size != 0) {
            object* p(o.via.array.ptr);
            s << *p;
            ++p;
            for(object* const pend(o.via.array.ptr + o.via.array.size);
                    p < pend; ++p) {
                s << ", " << *p;
            }
        }
        s << "]";
        break;

    case type::MAP:
        s << "{";
        if(o.via.map.size != 0) {
            object_kv* p(o.via.map.ptr);
            s << p->key << "=>" << p->val;
            ++p;
            for(object_kv* const pend(o.via.map.ptr + o.via.map.size);
                    p < pend; ++p) {
                s << ", " << p->key << "=>" << p->val;
            }
        }
        s << "}";
        break;

    default:
        // FIXME
        s << "#<UNKNOWN " << static_cast<uint16_t>(o.type) << ">";
    }
    return s;
}

}  // namespace msgpack

#include "msgpack/type.hpp"

#endif /* msgpack/object.hpp */

<commit_msg>Add inline for ODR compliance.<commit_after>//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2008-2010 FURUHASHI Sadayuki
//
//    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.
//
#ifndef MSGPACK_OBJECT_HPP
#define MSGPACK_OBJECT_HPP

#include "object.h"
#include "pack.hpp"
#include "zone.hpp"
#include <string.h>
#include <stdexcept>
#include <typeinfo>
#include <limits>
#include <ostream>

namespace msgpack {

class type_error : public std::bad_cast { };

namespace type {
    enum object_type {
        NIL                 = MSGPACK_OBJECT_NIL,
        BOOLEAN             = MSGPACK_OBJECT_BOOLEAN,
        POSITIVE_INTEGER    = MSGPACK_OBJECT_POSITIVE_INTEGER,
        NEGATIVE_INTEGER    = MSGPACK_OBJECT_NEGATIVE_INTEGER,
        DOUBLE              = MSGPACK_OBJECT_DOUBLE,
        STR                 = MSGPACK_OBJECT_STR,
        BIN                 = MSGPACK_OBJECT_BIN,
        ARRAY               = MSGPACK_OBJECT_ARRAY,
        MAP                 = MSGPACK_OBJECT_MAP
    };
}

struct object;
struct object_kv;

struct object_array {
    uint32_t size;
    object* ptr;
};

struct object_map {
    uint32_t size;
    object_kv* ptr;
};

struct object_str {
    uint32_t size;
    const char* ptr;
};

struct object_bin {
    uint32_t size;
    const char* ptr;
};

struct object {
    union union_type {
        bool boolean;
        uint64_t u64;
        int64_t  i64;
        double   dec;
        object_array array;
        object_map map;
        object_str str;
        object_bin bin;
    };

    type::object_type type;
    union_type via;

    bool is_nil() const { return type == type::NIL; }

    template <typename T>
    T as() const;

    template <typename T>
    void convert(T& v) const;
    template <typename T>
    void convert(T* v) const;

    object();

    object(msgpack_object o);

    template <typename T>
    explicit object(const T& v);

    template <typename T>
    object(const T& v, zone* z);

    template <typename T>
    object& operator=(const T& v);

    operator msgpack_object() const;

    struct with_zone;

private:
    struct implicit_type;

public:
    implicit_type convert() const;
};

struct object_kv {
    object key;
    object val;
};

struct object::with_zone : object {
    with_zone(msgpack::zone* zone) : zone(zone) { }
    msgpack::zone* zone;
private:
    with_zone();
};

struct object::implicit_type {
    implicit_type(object const& o) : obj(o) { }
    ~implicit_type() { }

    template <typename T>
    operator T() { return obj.as<T>(); }

private:
    object const& obj;
};

// obsolete
template <typename Type>
class define : public Type {
public:
    typedef Type msgpack_type;
    typedef define<Type> define_type;

    define() {}
    define(const msgpack_type& v) : msgpack_type(v) {}

    template <typename Packer>
    void msgpack_pack(Packer& o) const
    {
        o << static_cast<const msgpack_type&>(*this);
    }

    void msgpack_unpack(object const& o)
    {
        o >> static_cast<msgpack_type&>(*this);
    }
};

template <typename Stream>
template <typename T>
inline packer<Stream>& packer<Stream>::pack(const T& v)
{
    *this << v;
    return *this;
}

inline object& operator>> (object const& o, object& v)
{
    v = o;
    return v;
}

// convert operator
template <typename T>
inline T& operator>> (object const& o, T& v)
{
    v.msgpack_unpack(o.convert());
    return v;
}

namespace detail {
template <typename Stream, typename T>
struct packer_serializer {
    static packer<Stream>& pack(packer<Stream>& o, const T& v) {
        v.msgpack_pack(o);
        return o;
    }
};
}

// serialize operator
template <typename Stream, typename T>
inline packer<Stream>& operator<< (packer<Stream>& o, const T& v)
{
    return detail::packer_serializer<Stream, T>::pack(o, v);
}

// deconvert operator
template <typename T>
inline void operator<< (object::with_zone& o, const T& v)
{
    v.msgpack_object(static_cast<object*>(&o), o.zone);
}

inline bool operator==(const object& x, const object& y)
{
    if(x.type != y.type) { return false; }

    switch(x.type) {
    case type::NIL:
        return true;

    case type::BOOLEAN:
        return x.via.boolean == y.via.boolean;

    case type::POSITIVE_INTEGER:
        return x.via.u64 == y.via.u64;

    case type::NEGATIVE_INTEGER:
        return x.via.i64 == y.via.i64;

    case type::DOUBLE:
        return x.via.dec == y.via.dec;

    case type::STR:
        return x.via.str.size == y.via.str.size &&
            memcmp(x.via.str.ptr, y.via.str.ptr, x.via.str.size) == 0;

    case type::BIN:
        return x.via.bin.size == y.via.bin.size &&
            memcmp(x.via.bin.ptr, y.via.bin.ptr, x.via.bin.size) == 0;

    case type::ARRAY:
        if(x.via.array.size != y.via.array.size) {
            return false;
        } else if(x.via.array.size == 0) {
            return true;
        } else {
            object* px = x.via.array.ptr;
            object* const pxend = x.via.array.ptr + x.via.array.size;
            object* py = y.via.array.ptr;
            do {
                if(!(*px == *py)) {
                    return false;
                }
                ++px;
                ++py;
            } while(px < pxend);
            return true;
        }

    case type::MAP:
        if(x.via.map.size != y.via.map.size) {
            return false;
        } else if(x.via.map.size == 0) {
            return true;
        } else {
            object_kv* px = x.via.map.ptr;
            object_kv* const pxend = x.via.map.ptr + x.via.map.size;
            object_kv* py = y.via.map.ptr;
            do {
                if(!(px->key == py->key) || !(px->val == py->val)) {
                    return false;
                }
                ++px;
                ++py;
            } while(px < pxend);
            return true;
        }

    default:
        return false;
    }
}

template <typename T>
inline bool operator==(const object& x, const T& y)
try {
    return x == object(y);
} catch (msgpack::type_error&) {
    return false;
}

inline bool operator!=(const object& x, const object& y)
{ return !(x == y); }

template <typename T>
inline bool operator==(const T& y, const object x)
{ return x == y; }

template <typename T>
inline bool operator!=(const object& x, const T& y)
{ return !(x == y); }

template <typename T>
inline bool operator!=(const T& y, const object& x)
{ return x != y; }

inline object::implicit_type object::convert() const
{
    return implicit_type(*this);
}

template <typename T>
inline void object::convert(T& v) const
{
    *this >> v;
}

template <typename T>
inline void object::convert(T* v) const
{
    convert(*v);
}

template <typename T>
inline T object::as() const
{
    T v;
    convert(v);
    return v;
}

inline object::object()
{
    type = type::NIL;
}

template <typename T>
inline object::object(const T& v)
{
    *this << v;
}

template <typename T>
inline object& object::operator=(const T& v)
{
    *this = object(v);
    return *this;
}

template <typename T>
object::object(const T& v, zone* z)
{
    with_zone oz(z);
    oz << v;
    type = oz.type;
    via = oz.via;
}

inline object::object(msgpack_object o)
{
    // FIXME beter way?
    ::memcpy(this, &o, sizeof(o));
}

inline void operator<< (object& o, msgpack_object v)
{
    // FIXME beter way?
    ::memcpy(&o, &v, sizeof(v));
}

inline object::operator msgpack_object() const
{
    // FIXME beter way?
    msgpack_object obj;
    ::memcpy(&obj, this, sizeof(obj));
    return obj;
}

// obsolete
template <typename T>
inline void convert(T& v, object const& o)
{
    o.convert(v);
}

// obsolete
template <typename Stream, typename T>
inline void pack(packer<Stream>& o, const T& v)
{
    o.pack(v);
}

// obsolete
template <typename Stream, typename T>
inline void pack_copy(packer<Stream>& o, T v)
{
    pack(o, v);
}

template <typename Stream>
packer<Stream>& operator<< (packer<Stream>& o, const object& v)
{
    switch(v.type) {
    case type::NIL:
        o.pack_nil();
        return o;

    case type::BOOLEAN:
        if(v.via.boolean) {
            o.pack_true();
        } else {
            o.pack_false();
        }
        return o;

    case type::POSITIVE_INTEGER:
        o.pack_uint64(v.via.u64);
        return o;

    case type::NEGATIVE_INTEGER:
        o.pack_int64(v.via.i64);
        return o;

    case type::DOUBLE:
        o.pack_double(v.via.dec);
        return o;

    case type::STR:
        o.pack_str(v.via.str.size);
        o.pack_str_body(v.via.str.ptr, v.via.str.size);
        return o;

    case type::BIN:
        o.pack_bin(v.via.bin.size);
        o.pack_bin_body(v.via.bin.ptr, v.via.bin.size);
        return o;

    case type::ARRAY:
        o.pack_array(v.via.array.size);
        for(object* p(v.via.array.ptr),
                * const pend(v.via.array.ptr + v.via.array.size);
                p < pend; ++p) {
            o << *p;
        }
        return o;

    case type::MAP:
        o.pack_map(v.via.map.size);
        for(object_kv* p(v.via.map.ptr),
                * const pend(v.via.map.ptr + v.via.map.size);
                p < pend; ++p) {
            o << p->key;
            o << p->val;
        }
        return o;

    default:
        throw type_error();
    }
}

inline std::ostream& operator<< (std::ostream& s, const object& o)
{
    switch(o.type) {
    case type::NIL:
        s << "nil";
        break;

    case type::BOOLEAN:
        s << (o.via.boolean ? "true" : "false");
        break;

    case type::POSITIVE_INTEGER:
        s << o.via.u64;
        break;

    case type::NEGATIVE_INTEGER:
        s << o.via.i64;
        break;

    case type::DOUBLE:
        s << o.via.dec;
        break;

    case type::STR:
        (s << '"').write(o.via.str.ptr, o.via.str.size) << '"';
        break;

    case type::BIN:
        (s << '"').write(o.via.bin.ptr, o.via.bin.size) << '"';
        break;

    case type::ARRAY:
        s << "[";
        if(o.via.array.size != 0) {
            object* p(o.via.array.ptr);
            s << *p;
            ++p;
            for(object* const pend(o.via.array.ptr + o.via.array.size);
                    p < pend; ++p) {
                s << ", " << *p;
            }
        }
        s << "]";
        break;

    case type::MAP:
        s << "{";
        if(o.via.map.size != 0) {
            object_kv* p(o.via.map.ptr);
            s << p->key << "=>" << p->val;
            ++p;
            for(object_kv* const pend(o.via.map.ptr + o.via.map.size);
                    p < pend; ++p) {
                s << ", " << p->key << "=>" << p->val;
            }
        }
        s << "}";
        break;

    default:
        // FIXME
        s << "#<UNKNOWN " << static_cast<uint16_t>(o.type) << ">";
    }
    return s;
}

}  // namespace msgpack

#include "msgpack/type.hpp"

#endif /* msgpack/object.hpp */

<|endoftext|>