<commit_before>#ifndef ITER_PRODUCT_HPP_
#define ITER_PRODUCT_HPP_

#include "iterbase.hpp"

#include <iterator>
#include <tuple>
#include <utility>

namespace iter {
    template <typename... RestContainers>
    class Productor;

    template <typename... Containers>
    Productor<Containers...> product(Containers&&...);

    // specialization for at least 1 template argument
    template <typename Container, typename... RestContainers>
    class Productor <Container, RestContainers...> {
        static_assert(!std::is_rvalue_reference<Container>::value,
                "Itertools cannot be templated with rvalue references");

        friend Productor product<Container, RestContainers...>(
                Container&&, RestContainers&&...);

        template <typename... RC>
        friend class Productor;

        private:
            Container container;
            Productor<RestContainers...> rest_products;
            Productor(Container container, RestContainers&&... rest)
                : container(std::forward<Container>(container)),
                rest_products{std::forward<RestContainers>(rest)...}
            { }

        public:
            class Iterator {
                private:
                    using RestIter =
                        typename Productor<RestContainers...>::Iterator;

                    iterator_type<Container> iter;
                    const iterator_type<Container> begin;

                    RestIter rest_iter;
                    const RestIter rest_end;
                public:
                    constexpr static const bool is_base_iter = false;
                    Iterator(iterator_type<Container> it,
                            const RestIter& rest,
                            const RestIter& in_rest_end)
                        : iter{it},
                        begin{it},
                        rest_iter{rest},
                        rest_end{in_rest_end}
                    { }

                    void reset() {
                        this->iter = this->begin;
                    }

                    Iterator& operator++() {
                        ++this->rest_iter;
                        if (!(this->rest_iter != this->rest_end)) {
                            this->rest_iter.reset();
                            ++this->iter;
                        }
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->iter != other.iter &&
                            (RestIter::is_base_iter ||
                                this->rest_iter != other.rest_iter);
                    }

                    auto operator*() ->
                        decltype(std::tuple_cat(
                                    std::tuple<iterator_deref<Container>>{
                                        *this->iter},
                                    *this->rest_iter))
                    {
                        return std::tuple_cat(
                                std::tuple<iterator_deref<Container>>{
                                    *this->iter},
                                *this->rest_iter);
                    }
                    auto operator*() const ->
                        decltype(std::tuple_cat(
                                    std::tuple<const iterator_deref<Container>>{
                                        *this->iter},
                                    *this->rest_iter))
                    {
                        return std::tuple_cat(
                                std::tuple<const iterator_deref<Container>>{
                                    *this->iter},
                                *this->rest_iter);
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                    std::begin(this->rest_products),
                    std::end(this->rest_products)};
            }

            Iterator end() {
                return {std::end(this->container),
                    std::end(this->rest_products),
                    std::end(this->rest_products)};
            }
    };

    template <>
    class Productor<> {
        public:
            class Iterator {
                public:
                    constexpr static const bool is_base_iter = true;

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

                    void reset() { }

                    Iterator& operator++() {
                        return *this;
                    }

                    // see note in zip about base case operator!=
                    bool operator!=(const Iterator&) const {
                        return false;
                    }

                    std::tuple<> operator*() const {
                        return std::tuple<>{};
                    }
            };

            Iterator begin() {
                return {};
            }

            Iterator end() {
                return {};
            }
    };

    template <typename... Containers>
    Productor<Containers...> product(Containers&&... containers) {
        return {std::forward<Containers>(containers)...};
    }
}

#endif // #ifndef ITER_PRODUCT_HPP_
<commit_msg>removes const product operator*<commit_after>#ifndef ITER_PRODUCT_HPP_
#define ITER_PRODUCT_HPP_

#include "iterbase.hpp"

#include <iterator>
#include <tuple>
#include <utility>

namespace iter {
    template <typename... RestContainers>
    class Productor;

    template <typename... Containers>
    Productor<Containers...> product(Containers&&...);

    // specialization for at least 1 template argument
    template <typename Container, typename... RestContainers>
    class Productor <Container, RestContainers...> {
        static_assert(!std::is_rvalue_reference<Container>::value,
                "Itertools cannot be templated with rvalue references");

        friend Productor product<Container, RestContainers...>(
                Container&&, RestContainers&&...);

        template <typename... RC>
        friend class Productor;

        private:
            Container container;
            Productor<RestContainers...> rest_products;
            Productor(Container container, RestContainers&&... rest)
                : container(std::forward<Container>(container)),
                rest_products{std::forward<RestContainers>(rest)...}
            { }

        public:
            class Iterator {
                private:
                    using RestIter =
                        typename Productor<RestContainers...>::Iterator;

                    iterator_type<Container> iter;
                    const iterator_type<Container> begin;

                    RestIter rest_iter;
                    const RestIter rest_end;
                public:
                    constexpr static const bool is_base_iter = false;
                    Iterator(iterator_type<Container> it,
                            const RestIter& rest,
                            const RestIter& in_rest_end)
                        : iter{it},
                        begin{it},
                        rest_iter{rest},
                        rest_end{in_rest_end}
                    { }

                    void reset() {
                        this->iter = this->begin;
                    }

                    Iterator& operator++() {
                        ++this->rest_iter;
                        if (!(this->rest_iter != this->rest_end)) {
                            this->rest_iter.reset();
                            ++this->iter;
                        }
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->iter != other.iter &&
                            (RestIter::is_base_iter ||
                                this->rest_iter != other.rest_iter);
                    }

                    auto operator*() ->
                        decltype(std::tuple_cat(
                                    std::tuple<iterator_deref<Container>>{
                                        *this->iter},
                                    *this->rest_iter))
                    {
                        return std::tuple_cat(
                                std::tuple<iterator_deref<Container>>{
                                    *this->iter},
                                *this->rest_iter);
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                    std::begin(this->rest_products),
                    std::end(this->rest_products)};
            }

            Iterator end() {
                return {std::end(this->container),
                    std::end(this->rest_products),
                    std::end(this->rest_products)};
            }
    };

    template <>
    class Productor<> {
        public:
            class Iterator {
                public:
                    constexpr static const bool is_base_iter = true;

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

                    void reset() { }

                    Iterator& operator++() {
                        return *this;
                    }

                    // see note in zip about base case operator!=
                    bool operator!=(const Iterator&) const {
                        return false;
                    }

                    std::tuple<> operator*() const {
                        return std::tuple<>{};
                    }
            };

            Iterator begin() {
                return {};
            }

            Iterator end() {
                return {};
            }
    };

    template <typename... Containers>
    Productor<Containers...> product(Containers&&... containers) {
        return {std::forward<Containers>(containers)...};
    }
}

#endif // #ifndef ITER_PRODUCT_HPP_
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Project OSRM, Dennis Luxen, others
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.

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 HOLDER 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.

*/

#include "DescriptionFactory.h"

#include <osrm/Coordinate.h>

#include "../typedefs.h"
#include "../Algorithms/PolylineCompressor.h"
#include "../DataStructures/PhantomNodes.h"
#include "../DataStructures/RawRouteData.h"
#include "../DataStructures/SegmentInformation.h"
#include "../DataStructures/TurnInstructions.h"

DescriptionFactory::DescriptionFactory() : entireLength(0) { via_indices.push_back(0); }

std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }

void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
{
    start_phantom = source;
    const EdgeWeight segment_duration =
        (traversed_in_reverse ? source.reverse_weight : source.forward_weight);
    const TravelMode travel_mode =
          (traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
    AppendSegment(source.location,
                  PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration, travel_mode));
    BOOST_ASSERT(path_description.back().duration == segment_duration);
}

void DescriptionFactory::SetEndSegment(const PhantomNode &target,
                                       const bool traversed_in_reverse,
                                       const bool is_via_location)
{
    target_phantom = target;
    const EdgeWeight segment_duration =
        (traversed_in_reverse ? target.reverse_weight : target.forward_weight);
    const TravelMode travel_mode =
          (traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
    path_description.emplace_back(target.location,
                                  target.name_id,
                                  segment_duration,
                                  0.f,
                                  is_via_location ? TurnInstruction::ReachViaLocation
                                                  : TurnInstruction::NoTurn,
                                  true,
                                  true,
                                  travel_mode);
    BOOST_ASSERT(path_description.back().duration == segment_duration);
}

void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
                                       const PathData &path_point)
{
    //if the start location is on top of a node, the first movement might be zero-length,
    //in which case we dont' add a new description, but instead update the existing one
    if ((1 == path_description.size()) && (path_description.front().location == coordinate))
    {
        if (path_point.segment_duration>0)
        {
            path_description.front().name_id = path_point.name_id;
            path_description.front().travel_mode = path_point.travel_mode;
        }
        return;
    }

    // make sure mode changes are announced, even when there otherwise is no turn
    const TurnInstruction turn =
        (TurnInstruction::NoTurn == path_point.turn_instruction &&
        path_description.front().travel_mode != path_point.travel_mode &&
        path_point.segment_duration>0) ? TurnInstruction::GoStraight
                                       : path_point.turn_instruction;

    path_description.emplace_back(coordinate,
                                  path_point.name_id,
                                  path_point.segment_duration,
                                  0.f,
                                  turn,
                                  path_point.travel_mode);
}

JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
{
    if (return_encoded)
    {
        return polyline_compressor.printEncodedString(path_description);
    }
    return polyline_compressor.printUnencodedString(path_description);
}

void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
{
    summary.source_name_id = start_phantom.name_id;
    summary.target_name_id = target_phantom.name_id;
    summary.BuildDurationAndLengthStrings(distance, time);
}
<commit_msg>use lambda to decide turn value<commit_after>/*

Copyright (c) 2013, Project OSRM, Dennis Luxen, others
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.

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 HOLDER 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.

*/

#include "DescriptionFactory.h"

#include <osrm/Coordinate.h>

#include "../typedefs.h"
#include "../Algorithms/PolylineCompressor.h"
#include "../DataStructures/PhantomNodes.h"
#include "../DataStructures/RawRouteData.h"
#include "../DataStructures/SegmentInformation.h"
#include "../DataStructures/TurnInstructions.h"

DescriptionFactory::DescriptionFactory() : entireLength(0) { via_indices.push_back(0); }

std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }

void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
{
    start_phantom = source;
    const EdgeWeight segment_duration =
        (traversed_in_reverse ? source.reverse_weight : source.forward_weight);
    const TravelMode travel_mode =
          (traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
    AppendSegment(source.location,
                  PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration, travel_mode));
    BOOST_ASSERT(path_description.back().duration == segment_duration);
}

void DescriptionFactory::SetEndSegment(const PhantomNode &target,
                                       const bool traversed_in_reverse,
                                       const bool is_via_location)
{
    target_phantom = target;
    const EdgeWeight segment_duration =
        (traversed_in_reverse ? target.reverse_weight : target.forward_weight);
    const TravelMode travel_mode =
          (traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
    path_description.emplace_back(target.location,
                                  target.name_id,
                                  segment_duration,
                                  0.f,
                                  is_via_location ? TurnInstruction::ReachViaLocation
                                                  : TurnInstruction::NoTurn,
                                  true,
                                  true,
                                  travel_mode);
    BOOST_ASSERT(path_description.back().duration == segment_duration);
}

void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
                                       const PathData &path_point)
{
    //if the start location is on top of a node, the first movement might be zero-length,
    //in which case we dont' add a new description, but instead update the existing one
    if ((1 == path_description.size()) && (path_description.front().location == coordinate))
    {
        if (path_point.segment_duration>0)
        {
            path_description.front().name_id = path_point.name_id;
            path_description.front().travel_mode = path_point.travel_mode;
        }
        return;
    }

    // make sure mode changes are announced, even when there otherwise is no turn
    const TurnInstruction turn = [] -> TurnInstruction ()
    {
        if (TurnInstruction::NoTurn == path_point.turn_instruction &&
            path_description.front().travel_mode != path_point.travel_mode &&
            path_point.segment_duration>0)
        {
          return TurnInstruction::GoStraight;
        }
        else
        {
          return path_point.turn_instruction
        }
    }

    path_description.emplace_back(coordinate,
                                  path_point.name_id,
                                  path_point.segment_duration,
                                  0.f,
                                  turn,
                                  path_point.travel_mode);
}

JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
{
    if (return_encoded)
    {
        return polyline_compressor.printEncodedString(path_description);
    }
    return polyline_compressor.printUnencodedString(path_description);
}

void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
{
    summary.source_name_id = start_phantom.name_id;
    summary.target_name_id = target_phantom.name_id;
    summary.BuildDurationAndLengthStrings(distance, time);
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 - 2019, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/thread/posix/Backtrace.h>

#include <stingraykit/thread/Thread.h>
#include <stingraykit/function/bind.h>
#include <stingraykit/string/Hex.h>
#include <stingraykit/ScopeExit.h>

#ifdef HAVE_BFD_BACKTRACE
#	include <bfd.h>
#endif
#include <execinfo.h>

#include <iosfwd>
#include <sstream>

#define BACKTRACE_DEMANGLE 0

#if BACKTRACE_DEMANGLE
#	include <cxxabi.h>
#endif

#define BACKTRACE_FRAMES (64)

namespace stingray {
namespace posix
{

	static Mutex _backtrace_mutex;

	Backtrace::Backtrace()
	{
		_backtrace.resize(BACKTRACE_FRAMES);
		int frames = backtrace(&_backtrace[0], _backtrace.size());
		if (frames < 0)
			frames = 0;
		_backtrace.resize(frames);
	}

#ifdef HAVE_BFD_BACKTRACE
	struct bfd_holder {
		struct bfd *abfd;
		asymbol **symbols;
		bfd_boolean dynamic;

		bfd_holder(struct bfd *bfd = NULL): abfd(bfd), symbols(NULL) { bfd_init(); }
		~bfd_holder() { close(); }

		bool open(const char *fname)
		{
			close();
			abfd = bfd_openr(fname, NULL);
			if (!abfd)
				return false;
			if (!bfd_check_format (abfd, bfd_object))
			{
				bfd_close(abfd);
				abfd = NULL;
				return false;
			}
			return true;
		}

		void close()
		{
			if (symbols)
			{
				free(symbols);
				symbols = NULL;
			}
			if (abfd)
			{
				bfd_close(abfd);
				abfd = NULL;
			}
		}

		asymbol **get_symbols()
		{
			if (!symbols)
			{
				unsigned size;
				long count = bfd_read_minisymbols(abfd, dynamic, reinterpret_cast<void **>(&symbols), &size);
				if (count == 0)
				{
					dynamic = 1;
					count = bfd_read_minisymbols(abfd, dynamic, reinterpret_cast<void **>(&symbols), &size);
					if (count == 0)
					{
						return NULL;
					}
				}
			}
			return symbols;
		}

		bool find_in_section(asection *section, bfd_vma addr) const
		{
			if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
				return false;

			bfd_vma vma = bfd_get_section_vma(abfd, section);
			if (addr < vma)
				return false;

			bfd_size_type size = bfd_section_size(abfd, section);
			return addr < vma + size;
		}
		operator struct bfd* () { return abfd; }
		struct bfd* operator ->() { return abfd; }
	} bfd;

	std::string Backtrace::Get() const
	{
		MutexLock l(_backtrace_mutex);
		if (!bfd.abfd)
		{
			if (!bfd.open("/proc/self/exe"))
				return "cannot open /proc/self/exe";
		}
		asymbol **symbols = bfd.get_symbols();
		if (!symbols)
			return "cannot load symbols";

		string_ostream backtrace;
		try
		{
			for(size_t i = 0; i < _backtrace.size(); ++i)
			{
				bfd_vma addr = (bfd_vma)_backtrace[i];
				for(asection *section = bfd->sections; section != bfd->section_last; section = section->next)
				{
					if (bfd.find_in_section(section, addr))
					{
						bfd_vma vma = bfd_get_section_vma(bfd.abfd, section);
						const char *filename, *functionname;
						unsigned line;
						if (bfd_find_nearest_line(bfd.abfd, section, symbols, addr - vma, &filename, &functionname, &line))
						{
							backtrace << "0x" << Hex(vma) << "\t" << filename << ":" << line << "\t";
#if BACKTRACE_DEMANGLE
							int status;
							char *buf = abi::__cxa_demangle(functionname, 0, 0, &status);
							ScopeExitInvoker sei(Bind(&free, buf));
							if (buf && status == 0)
								backtrace << buf;
							else
								backtrace << functionname;
							backtrace << "\n";
#else
							backtrace << functionname << "\n";
#endif
						}
						else
						{
							//show only addr
							backtrace << "0x" << Hex(vma) << "?" << "\n";
						}
					}
				}
			}
		} catch(const std::exception &e)
		{
			return e.what();
		}
		return backtrace.str();
	}

#else

	std::string Backtrace::Get() const
	{
		string_ostream backtrace;

		for(size_t i = 0; i < _backtrace.size(); ++i)
			backtrace << ToHex((unsigned long)_backtrace[i], 8) << " ";

		return backtrace.str();
	}

#endif

}}
<commit_msg>posix/Backtrace: fix compilation of bfd backtrace<commit_after>// Copyright (c) 2011 - 2019, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/thread/posix/Backtrace.h>

#include <stingraykit/thread/Thread.h>
#include <stingraykit/function/bind.h>
#include <stingraykit/string/Hex.h>
#include <stingraykit/ScopeExit.h>

#ifdef HAVE_BFD_BACKTRACE
#	include <bfd.h>
#endif
#include <execinfo.h>

#include <iosfwd>
#include <sstream>

#define BACKTRACE_DEMANGLE 0

#if BACKTRACE_DEMANGLE
#	include <cxxabi.h>
#endif

#define BACKTRACE_FRAMES (64)

namespace stingray {
namespace posix
{

	static Mutex _backtrace_mutex;

	Backtrace::Backtrace()
	{
		_backtrace.resize(BACKTRACE_FRAMES);
		int frames = backtrace(&_backtrace[0], _backtrace.size());
		if (frames < 0)
			frames = 0;
		_backtrace.resize(frames);
	}

#ifdef HAVE_BFD_BACKTRACE
	struct bfd_holder {
		struct bfd *abfd;
		asymbol **symbols;
		bfd_boolean dynamic;

		bfd_holder(struct bfd *bfd = NULL): abfd(bfd), symbols(NULL) { bfd_init(); }
		~bfd_holder() { close(); }

		bool open(const char *fname)
		{
			close();
			abfd = bfd_openr(fname, NULL);
			if (!abfd)
				return false;
			if (!bfd_check_format (abfd, bfd_object))
			{
				bfd_close(abfd);
				abfd = NULL;
				return false;
			}
			return true;
		}

		void close()
		{
			if (symbols)
			{
				free(symbols);
				symbols = NULL;
			}
			if (abfd)
			{
				bfd_close(abfd);
				abfd = NULL;
			}
		}

		asymbol **get_symbols()
		{
			if (!symbols)
			{
				unsigned size;
				long count = bfd_read_minisymbols(abfd, dynamic, reinterpret_cast<void **>(&symbols), &size);
				if (count == 0)
				{
					dynamic = 1;
					count = bfd_read_minisymbols(abfd, dynamic, reinterpret_cast<void **>(&symbols), &size);
					if (count == 0)
					{
						return NULL;
					}
				}
			}
			return symbols;
		}

		bool find_in_section(asection *section, bfd_vma addr) const
		{
			if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
				return false;

			bfd_vma vma = bfd_get_section_vma(abfd, section);
			if (addr < vma)
				return false;

			bfd_size_type size = bfd_section_size(abfd, section);
			return addr < vma + size;
		}
		operator struct bfd* () { return abfd; }
		struct bfd* operator ->() { return abfd; }
	} bfd;

	std::string Backtrace::Get() const
	{
		MutexLock l(_backtrace_mutex);
		if (!bfd.abfd)
		{
			if (!bfd.open("/proc/self/exe"))
				return "cannot open /proc/self/exe";
		}
		asymbol **symbols = bfd.get_symbols();
		if (!symbols)
			return "cannot load symbols";

		string_ostream backtrace;
		try
		{
			for(size_t i = 0; i < _backtrace.size(); ++i)
			{
				bfd_vma addr = (bfd_vma)_backtrace[i];
				for(asection *section = bfd->sections; section != bfd->section_last; section = section->next)
				{
					if (bfd.find_in_section(section, addr))
					{
						bfd_vma vma = bfd_get_section_vma(bfd.abfd, section);
						const char *filename, *functionname;
						unsigned line;
						if (bfd_find_nearest_line(bfd.abfd, section, symbols, addr - vma, &filename, &functionname, &line))
						{
							backtrace << "0x" << ToHex(vma) << "\t" << filename << ":" << line << "\t";
#if BACKTRACE_DEMANGLE
							int status;
							char *buf = abi::__cxa_demangle(functionname, 0, 0, &status);
							ScopeExitInvoker sei(Bind(&free, buf));
							if (buf && status == 0)
								backtrace << buf;
							else
								backtrace << functionname;
							backtrace << "\n";
#else
							backtrace << functionname << "\n";
#endif
						}
						else
						{
							//show only addr
							backtrace << "0x" << ToHex(vma) << "?" << "\n";
						}
					}
				}
			}
		} catch(const std::exception &e)
		{
			return e.what();
		}
		return backtrace.str();
	}

#else

	std::string Backtrace::Get() const
	{
		string_ostream backtrace;

		for(size_t i = 0; i < _backtrace.size(); ++i)
			backtrace << ToHex((unsigned long)_backtrace[i], 8) << " ";

		return backtrace.str();
	}

#endif

}}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// This source file is part of Hect.
//
// Copyright (c) 2016 Colin Hill
//
// 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 "Format.h"

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

namespace hect
{

std::string format(const char* fmt, ...)
{
    va_list args;
    va_start(args, fmt);

    // Check the length of the resulting string and allocate the string
    int length = vsnprintf(nullptr, 0, fmt, args);
    std::string result(length, '\0');

    // Print to the result
    vsprintf(&result[0], fmt, args);

    va_end(args);

    return result;
}

}<commit_msg>Revert "Change format() to no longer use a static buffer"<commit_after>///////////////////////////////////////////////////////////////////////////////
// This source file is part of Hect.
//
// Copyright (c) 2016 Colin Hill
//
// 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 "Format.h"

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

namespace hect
{

std::string format(const char* fmt, ...)
{
    static char buffer[16384];

    va_list args;

    va_start(args, fmt);

    vsprintf(buffer, fmt, args);

    va_end(args);

    return std::string(buffer);
}

}<|endoftext|>


<commit_before><commit_msg>Add comments to optinterp2<commit_after><|endoftext|>


<commit_before><commit_msg>Fix rename and implement ClearDoc<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <cstddef>
#include <cstdint>
#include <string>

namespace ouzel
{
    class Vector3;
    class Vector4;

    class Color
    {
    public:
        enum
        {
            BLACK = 0x000000ff,
            RED = 0xff0000ff,
            MAGENTA = 0xff00ffff,
            GREEN = 0x00ff00ff,
            CYAN = 0x00ffffff,
            BLUE = 0x0000ffff,
            YELLOW = 0xffff00ff,
            WHITE = 0xffffffff,
            GRAY = 0x808080ff
        };

        uint8_t r = 0;
        uint8_t g = 0;
        uint8_t b = 0;
        uint8_t a = 0;

        Color()
        {
        }

        Color(uint32_t color):
            r(static_cast<uint8_t>((color & 0xFF000000) >> 24)),
            g(static_cast<uint8_t>((color & 0x00FF0000) >> 16)),
            b(static_cast<uint8_t>((color & 0x0000FF00) >> 8)),
            a(static_cast<uint8_t>(color & 0x000000FF))
        {
        }

        Color& operator=(uint32_t color)
        {
            r = static_cast<uint8_t>((color & 0xFF000000) >> 24);
            g = static_cast<uint8_t>((color & 0x00FF0000) >> 16);
            b = static_cast<uint8_t>((color & 0x0000FF00) >> 8);
            a = static_cast<uint8_t>(color & 0x000000FF);

            return *this;
        }

        Color(const std::string& color);
        Color& operator=(const std::string& color);

        Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 0xFF):
            r(red), g(green), b(blue), a(alpha)
        {
        }

        Color(const Vector3& vec);
        Color& operator=(const Vector3& vec);

        Color(const Vector4& vec);
        Color& operator=(const Vector4& vec);

        float normR() const { return r / 255.0f; }
        float normG() const { return g / 255.0f; }
        float normB() const { return b / 255.0f; }
        float normA() const { return a / 255.0f; }

        uint32_t getIntValue() const
        {
            return (static_cast<uint32_t>(r) << 24) |
                   (static_cast<uint32_t>(g) << 16) |
                   (static_cast<uint32_t>(b) << 8) |
                   static_cast<uint32_t>(a);
        }
    };
} // namespace ouzel
<commit_msg>Use const instead of enum for color constants<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <cstddef>
#include <cstdint>
#include <string>

namespace ouzel
{
    class Vector3;
    class Vector4;

    class Color
    {
    public:
        static const uint32_t BLACK = 0x000000ff;
        static const uint32_t RED = 0xff0000ff;
        static const uint32_t MAGENTA = 0xff00ffff;
        static const uint32_t GREEN = 0x00ff00ff;
        static const uint32_t CYAN = 0x00ffffff;
        static const uint32_t BLUE = 0x0000ffff;
        static const uint32_t YELLOW = 0xffff00ff;
        static const uint32_t WHITE = 0xffffffff;
        static const uint32_t GRAY = 0x808080ff;

        uint8_t r = 0;
        uint8_t g = 0;
        uint8_t b = 0;
        uint8_t a = 0;

        Color()
        {
        }

        Color(uint32_t color):
            r(static_cast<uint8_t>((color & 0xFF000000) >> 24)),
            g(static_cast<uint8_t>((color & 0x00FF0000) >> 16)),
            b(static_cast<uint8_t>((color & 0x0000FF00) >> 8)),
            a(static_cast<uint8_t>(color & 0x000000FF))
        {
        }

        Color& operator=(uint32_t color)
        {
            r = static_cast<uint8_t>((color & 0xFF000000) >> 24);
            g = static_cast<uint8_t>((color & 0x00FF0000) >> 16);
            b = static_cast<uint8_t>((color & 0x0000FF00) >> 8);
            a = static_cast<uint8_t>(color & 0x000000FF);

            return *this;
        }

        Color(const std::string& color);
        Color& operator=(const std::string& color);

        Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 0xFF):
            r(red), g(green), b(blue), a(alpha)
        {
        }

        Color(const Vector3& vec);
        Color& operator=(const Vector3& vec);

        Color(const Vector4& vec);
        Color& operator=(const Vector4& vec);

        float normR() const { return r / 255.0f; }
        float normG() const { return g / 255.0f; }
        float normB() const { return b / 255.0f; }
        float normA() const { return a / 255.0f; }

        uint32_t getIntValue() const
        {
            return (static_cast<uint32_t>(r) << 24) |
                   (static_cast<uint32_t>(g) << 16) |
                   (static_cast<uint32_t>(b) << 8) |
                   static_cast<uint32_t>(a);
        }
    };
} // namespace ouzel
<|endoftext|>


<commit_before>#include "ConstrainedDecoding.h"
#include "moses/Hypothesis.h"
#include "moses/Manager.h"
#include "moses/ChartHypothesis.h"
#include "moses/ChartManager.h"
#include "moses/StaticData.h"
#include "moses/InputFileStream.h"
#include "moses/Util.h"
#include "util/exception.hh"

using namespace std;

namespace Moses
{
ConstrainedDecodingState::ConstrainedDecodingState(const Hypothesis &hypo)
{
  hypo.GetOutputPhrase(m_outputPhrase);
}

ConstrainedDecodingState::ConstrainedDecodingState(const ChartHypothesis &hypo)
{
  hypo.GetOutputPhrase(m_outputPhrase);
}

int ConstrainedDecodingState::Compare(const FFState& other) const
{
  const ConstrainedDecodingState &otherFF = static_cast<const ConstrainedDecodingState&>(other);
  bool ret = 	m_outputPhrase.Compare(otherFF.m_outputPhrase);
  return ret;
}

//////////////////////////////////////////////////////////////////
void ConstrainedDecoding::Load()
{
  const StaticData &staticData = StaticData::Instance();
  bool addBeginEndWord = (staticData.GetSearchAlgorithm() == ChartDecoding) || (staticData.GetSearchAlgorithm() == ChartIncremental);

  InputFileStream constraintFile(m_path);
  std::string line;
  long sentenceID = staticData.GetStartTranslationId() - 1;
  while (getline(constraintFile, line)) {
    vector<string> vecStr = Tokenize(line, "\t");

    Phrase phrase(0);
    if (vecStr.size() == 1) {
      sentenceID++;
      phrase.CreateFromString(Output, staticData.GetOutputFactorOrder(), vecStr[0], staticData.GetFactorDelimiter(), NULL);
    } else if (vecStr.size() == 2) {
      sentenceID = Scan<long>(vecStr[0]);
      phrase.CreateFromString(Output, staticData.GetOutputFactorOrder(), vecStr[1], staticData.GetFactorDelimiter(), NULL);
    } else {
      UTIL_THROW(util::Exception, "Reference file not loaded");
    }

    if (addBeginEndWord) {
      phrase.InitStartEndWord();
    }
    m_constraints.insert(make_pair(sentenceID,phrase));

  }
}

std::vector<float> ConstrainedDecoding::DefaultWeights() const
{
  UTIL_THROW_IF2(m_numScoreComponents != 1,
		  "ConstrainedDecoding must only have 1 score");
  vector<float> ret(1, 1);
  return ret;
}

template <class H, class M>
const Phrase *GetConstraint(const std::map<long,Phrase> &constraints, const H &hypo)
{
  const M &mgr = hypo.GetManager();
  const InputType &input = mgr.GetSource();
  long id = input.GetTranslationId();

  map<long,Phrase>::const_iterator iter;
  iter = constraints.find(id);

  if (iter == constraints.end()) {
    UTIL_THROW(util::Exception, "Couldn't find reference " << id);

    return NULL;
  } else {
    return &iter->second;
  }
}

FFState* ConstrainedDecoding::Evaluate(
  const Hypothesis& hypo,
  const FFState* prev_state,
  ScoreComponentCollection* accumulator) const
{
  const Phrase *ref = GetConstraint<Hypothesis, Manager>(m_constraints, hypo);
  assert(ref);

  ConstrainedDecodingState *ret = new ConstrainedDecodingState(hypo);
  const Phrase &outputPhrase = ret->GetPhrase();

  size_t searchPos = ref->Find(outputPhrase, m_maxUnknowns);

  float score;
  if (hypo.IsSourceCompleted()) {
    // translated entire sentence.
    score = (searchPos == 0) && (ref->GetSize() == outputPhrase.GetSize())
            ? 0 : - std::numeric_limits<float>::infinity();
  } else {
    score = (searchPos != NOT_FOUND) ? 0 : - std::numeric_limits<float>::infinity();
  }

  accumulator->PlusEquals(this, score);

  return ret;
}

FFState* ConstrainedDecoding::EvaluateChart(
  const ChartHypothesis &hypo,
  int /* featureID - used to index the state in the previous hypotheses */,
  ScoreComponentCollection* accumulator) const
{
  const Phrase *ref = GetConstraint<ChartHypothesis, ChartManager>(m_constraints, hypo);
  assert(ref);

  const ChartManager &mgr = hypo.GetManager();
  const Sentence &source = static_cast<const Sentence&>(mgr.GetSource());

  ConstrainedDecodingState *ret = new ConstrainedDecodingState(hypo);
  const Phrase &outputPhrase = ret->GetPhrase();
  size_t searchPos = ref->Find(outputPhrase, m_maxUnknowns);

  float score;
  if (hypo.GetCurrSourceRange().GetStartPos() == 0 &&
      hypo.GetCurrSourceRange().GetEndPos() == source.GetSize() - 1) {
    // translated entire sentence.
    score = (searchPos == 0) && (ref->GetSize() == outputPhrase.GetSize())
            ? 0 : - std::numeric_limits<float>::infinity();
  } else {
    score = (searchPos != NOT_FOUND) ? 0 : - std::numeric_limits<float>::infinity();
  }

  accumulator->PlusEquals(this, score);

  return ret;
}

void ConstrainedDecoding::SetParameter(const std::string& key, const std::string& value)
{
  if (key == "path") {
    m_path = value;
  } else if (key == "max-unknowns") {
    m_maxUnknowns = Scan<int>(value);
  } else {
    StatefulFeatureFunction::SetParameter(key, value);
  }
}

}

<commit_msg>bug in constrained decoding<commit_after>#include "ConstrainedDecoding.h"
#include "moses/Hypothesis.h"
#include "moses/Manager.h"
#include "moses/ChartHypothesis.h"
#include "moses/ChartManager.h"
#include "moses/StaticData.h"
#include "moses/InputFileStream.h"
#include "moses/Util.h"
#include "util/exception.hh"

using namespace std;

namespace Moses
{
ConstrainedDecodingState::ConstrainedDecodingState(const Hypothesis &hypo)
{
  hypo.GetOutputPhrase(m_outputPhrase);
}

ConstrainedDecodingState::ConstrainedDecodingState(const ChartHypothesis &hypo)
{
  hypo.GetOutputPhrase(m_outputPhrase);
}

int ConstrainedDecodingState::Compare(const FFState& other) const
{
  const ConstrainedDecodingState &otherFF = static_cast<const ConstrainedDecodingState&>(other);
  int ret = 	m_outputPhrase.Compare(otherFF.m_outputPhrase);
  return ret;
}

//////////////////////////////////////////////////////////////////
void ConstrainedDecoding::Load()
{
  const StaticData &staticData = StaticData::Instance();
  bool addBeginEndWord = (staticData.GetSearchAlgorithm() == ChartDecoding) || (staticData.GetSearchAlgorithm() == ChartIncremental);

  InputFileStream constraintFile(m_path);
  std::string line;
  long sentenceID = staticData.GetStartTranslationId() - 1;
  while (getline(constraintFile, line)) {
    vector<string> vecStr = Tokenize(line, "\t");

    Phrase phrase(0);
    if (vecStr.size() == 1) {
      sentenceID++;
      phrase.CreateFromString(Output, staticData.GetOutputFactorOrder(), vecStr[0], staticData.GetFactorDelimiter(), NULL);
    } else if (vecStr.size() == 2) {
      sentenceID = Scan<long>(vecStr[0]);
      phrase.CreateFromString(Output, staticData.GetOutputFactorOrder(), vecStr[1], staticData.GetFactorDelimiter(), NULL);
    } else {
      UTIL_THROW(util::Exception, "Reference file not loaded");
    }

    if (addBeginEndWord) {
      phrase.InitStartEndWord();
    }
    m_constraints.insert(make_pair(sentenceID,phrase));

  }
}

std::vector<float> ConstrainedDecoding::DefaultWeights() const
{
  UTIL_THROW_IF2(m_numScoreComponents != 1,
		  "ConstrainedDecoding must only have 1 score");
  vector<float> ret(1, 1);
  return ret;
}

template <class H, class M>
const Phrase *GetConstraint(const std::map<long,Phrase> &constraints, const H &hypo)
{
  const M &mgr = hypo.GetManager();
  const InputType &input = mgr.GetSource();
  long id = input.GetTranslationId();

  map<long,Phrase>::const_iterator iter;
  iter = constraints.find(id);

  if (iter == constraints.end()) {
    UTIL_THROW(util::Exception, "Couldn't find reference " << id);

    return NULL;
  } else {
    return &iter->second;
  }
}

FFState* ConstrainedDecoding::Evaluate(
  const Hypothesis& hypo,
  const FFState* prev_state,
  ScoreComponentCollection* accumulator) const
{
  const Phrase *ref = GetConstraint<Hypothesis, Manager>(m_constraints, hypo);
  assert(ref);

  ConstrainedDecodingState *ret = new ConstrainedDecodingState(hypo);
  const Phrase &outputPhrase = ret->GetPhrase();

  size_t searchPos = ref->Find(outputPhrase, m_maxUnknowns);

  float score;
  if (hypo.IsSourceCompleted()) {
    // translated entire sentence.
    score = (searchPos == 0) && (ref->GetSize() == outputPhrase.GetSize())
            ? 0 : - std::numeric_limits<float>::infinity();
  } else {
    score = (searchPos != NOT_FOUND) ? 0 : - std::numeric_limits<float>::infinity();
  }

  accumulator->PlusEquals(this, score);

  return ret;
}

FFState* ConstrainedDecoding::EvaluateChart(
  const ChartHypothesis &hypo,
  int /* featureID - used to index the state in the previous hypotheses */,
  ScoreComponentCollection* accumulator) const
{
  const Phrase *ref = GetConstraint<ChartHypothesis, ChartManager>(m_constraints, hypo);
  assert(ref);

  const ChartManager &mgr = hypo.GetManager();
  const Sentence &source = static_cast<const Sentence&>(mgr.GetSource());

  ConstrainedDecodingState *ret = new ConstrainedDecodingState(hypo);
  const Phrase &outputPhrase = ret->GetPhrase();
  size_t searchPos = ref->Find(outputPhrase, m_maxUnknowns);

  float score;
  if (hypo.GetCurrSourceRange().GetStartPos() == 0 &&
      hypo.GetCurrSourceRange().GetEndPos() == source.GetSize() - 1) {
    // translated entire sentence.
    score = (searchPos == 0) && (ref->GetSize() == outputPhrase.GetSize())
            ? 0 : - std::numeric_limits<float>::infinity();
  } else {
    score = (searchPos != NOT_FOUND) ? 0 : - std::numeric_limits<float>::infinity();
  }

  accumulator->PlusEquals(this, score);

  return ret;
}

void ConstrainedDecoding::SetParameter(const std::string& key, const std::string& value)
{
  if (key == "path") {
    m_path = value;
  } else if (key == "max-unknowns") {
    m_maxUnknowns = Scan<int>(value);
  } else {
    StatefulFeatureFunction::SetParameter(key, value);
  }
}

}

<|endoftext|>


<commit_before>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015-2018  Vladimir Menshakov

    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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <usb/BufferAllocator.h>
#include <usb/Device.h>
#include <Exception.h>
#include <mtp/usb/TimeoutException.h>
#include <mtp/usb/DeviceBusyException.h>
#include <mtp/usb/DeviceNotFoundException.h>
#include <mtp/ByteArray.h>
#include <mtp/log.h>

#include <sys/ioctl.h>
#include <sys/time.h>
#include <poll.h>
#include <signal.h>

#include "linux/usbdevice_fs.h"

#define IOCTL(FD, ...) do \
{ \
	int r = ioctl(FD, __VA_ARGS__); \
	if (r < 0) \
	{ \
		if (errno == EBUSY) \
			throw DeviceBusyException(FD); \
		else if (errno == ENODEV) \
			throw DeviceNotFoundException(); \
		else \
			throw posix::Exception("ioctl(" #__VA_ARGS__ ")"); \
	} \
} while(false)

namespace mtp { namespace usb
{

	InterfaceToken::InterfaceToken(int fd, unsigned interfaceNumber): _fd(fd), _interfaceNumber(interfaceNumber)
	{
		IOCTL(_fd, USBDEVFS_CLAIMINTERFACE, &interfaceNumber);
	}

	InterfaceToken::~InterfaceToken()
	{
		ioctl(_fd, USBDEVFS_RELEASEINTERFACE, &_interfaceNumber);
	}

#define PRINT_CAP(CAP, NAME) \
	if (capabilities & (CAP)) \
	{ \
		debug(NAME " "); \
		capabilities &= ~(CAP); \
	}

	Device::Device(int fd, const EndpointPtr &controlEp): _fd(fd), _capabilities(0), _controlEp(controlEp)
	{
		try
		{ IOCTL(_fd.Get(), USBDEVFS_RESET); }
		catch(const std::exception &ex)
		{ error("resetting control point failed: ", ex.what()); }

		try { IOCTL(_fd.Get(), USBDEVFS_GET_CAPABILITIES, &_capabilities); }
		catch(const std::exception &ex)
		{ error("get usbfs capabilities failed: ", ex.what()); }

		debug("capabilities = 0x", hex(_capabilities, 8));
		bool mmap = _capabilities & USBDEVFS_CAP_MMAP;
		//disable mmap allocation for now, see https://github.com/whoozle/android-file-transfer-linux/issues/194
#if 1
		mmap = false;
#endif
		_bufferAllocator = std::make_shared<BufferAllocator>(mmap? fd: -1);

		if (_capabilities)
		{
			u32 capabilities = _capabilities;
			PRINT_CAP(USBDEVFS_CAP_ZERO_PACKET, "<zero-packet>");
			PRINT_CAP(USBDEVFS_CAP_BULK_CONTINUATION, "<bulk-continuation>");
			PRINT_CAP(USBDEVFS_CAP_NO_PACKET_SIZE_LIM, "<no-packet-size-limit>");
			PRINT_CAP(USBDEVFS_CAP_BULK_SCATTER_GATHER, "<bulk-scatter-gather>");
			PRINT_CAP(USBDEVFS_CAP_REAP_AFTER_DISCONNECT, "<reap-after-disconnect>");
			PRINT_CAP(USBDEVFS_CAP_MMAP, "<mmap>");
			PRINT_CAP(USBDEVFS_CAP_DROP_PRIVILEGES, "<drop-privileges>");
			if (capabilities)
				debug("<unknown capability 0x", hex(capabilities, 2), ">");
		}
		else
			debug("[none]\n");
	}

	Device::~Device()
	{ }

	int Device::GetConfiguration() const
	{
		return 0;
	}

	void Device::SetConfiguration(int idx)
	{
		error("SetConfiguration(", idx, "): not implemented");
	}

	struct Device::Urb : usbdevfs_urb, Noncopyable
	{
		static const int 		MaxBufferSize = 4096;
		BufferAllocator &		Allocator;
		int						Fd;
		int						PacketSize;
		Buffer					DataBuffer;

		Urb(BufferAllocator & allocator, int fd, u8 urbType, const EndpointPtr & ep):
			usbdevfs_urb(),
			Allocator(allocator),
			Fd(fd),
			PacketSize(ep->GetMaxPacketSize()),
			DataBuffer(Allocator.Allocate(std::max(PacketSize, MaxBufferSize / PacketSize * PacketSize)))
		{
			type			= urbType;
			endpoint		= ep->GetAddress();
			buffer			= DataBuffer.GetData();
			buffer_length	= DataBuffer.GetSize();
		}

		usbdevfs_urb *GetKernelUrb()
		{ return static_cast<usbdevfs_urb *>(this); }

		~Urb()
		{ Allocator.Free(DataBuffer); }

		size_t GetTransferSize() const
		{ return DataBuffer.GetSize(); }

		void Submit()
		{
			IOCTL(Fd, USBDEVFS_SUBMITURB, GetKernelUrb());
		}

		void Discard()
		{
			int r = ioctl(Fd, USBDEVFS_DISCARDURB, GetKernelUrb());
			if (r != 0)
			{
				perror("ioctl(USBDEVFS_DISCARDURB)");
			}
		}

		size_t Send(const IObjectInputStreamPtr &inputStream, size_t size)
		{
			if (size > DataBuffer.GetSize())
				throw std::logic_error("invalid size passed to Send");
			auto data = DataBuffer.GetData();
			size_t r = inputStream->Read(data, size);
			//HexDump("write", ByteArray(data, data + r), true);
			buffer_length = r;
			return r;
		}

		size_t Send(const ByteArray &inputData)
		{
			size_t r = std::min(DataBuffer.GetSize(), inputData.size());
			std::copy(inputData.data(), inputData.data() + r, DataBuffer.GetData());
			buffer_length = r;
			return r;
		}

		size_t Recv(const IObjectOutputStreamPtr &outputStream)
		{
			auto data = DataBuffer.GetData();
			//HexDump("read", ByteArray(data, data + actual_length), true);
			return outputStream->Write(data, actual_length);
		}

		template<unsigned Flag>
		void SetFlag(bool value)
		{
			if (value)
				flags |= Flag;
			else
				flags &= ~Flag;
		}

		void SetContinuationFlag(bool continuation)
		{ SetFlag<USBDEVFS_URB_BULK_CONTINUATION>(continuation); }

		void SetZeroPacketFlag(bool zero)
		{ SetFlag<USBDEVFS_URB_ZERO_PACKET>(zero); }
	};

	void * Device::Reap(int timeout)
	{
		timeval started = {};
		if (gettimeofday(&started, NULL) == -1)
			throw posix::Exception("gettimeofday");

		pollfd fd = {};
		fd.fd		= _fd.Get();
		fd.events	= POLLOUT | POLLWRNORM;
		int r = poll(&fd, 1, timeout);

		timeval now = {};
		if (gettimeofday(&now, NULL) == -1)
			throw posix::Exception("gettimeofday");

		if (r < 0)
			throw posix::Exception("poll");

		if (r == 0 && timeout > 0)
		{
			int ms = (now.tv_sec - started.tv_sec) * 1000 + (now.tv_usec - started.tv_usec) / 1000;
			error(ms, " ms since the last poll call");
		}
		auto urb = AsyncReap();
		if (urb)
			return urb;
		else
			throw TimeoutException("timeout reaping usb urb");
	}

	void * Device::AsyncReap()
	{
		usbdevfs_urb *urb;
		int r = ioctl(_fd.Get(), USBDEVFS_REAPURBNDELAY, &urb);
		if (r == 0)
			return urb;
		else if (errno == EAGAIN)
			return nullptr;
		else
			throw posix::Exception("ioctl(USBDEVFS_REAPURBNDELAY)");
	}

	void Device::ClearHalt(const EndpointPtr & ep)
	{
		try
		{ unsigned index = ep->GetAddress(); IOCTL(_fd.Get(), USBDEVFS_CLEAR_HALT, &index); }
		catch(const std::exception &ex)
		{ error("clearing halt status for ep ", hex(ep->GetAddress(), 2), ": ", ex.what()); }
	}

	void Device::Submit(Urb *urb, int timeout)
	{
		urb->Submit();
		try
		{
			while(true)
			{
				usbdevfs_urb * completedKernelUrb = static_cast<usbdevfs_urb *>(Reap(timeout));
				if (urb->GetKernelUrb() != completedKernelUrb)
				{
					error("got unknown urb: ", completedKernelUrb);
					continue;
				}
				else
					break;
			}
		}
		catch(const TimeoutException &ex)
		{
			urb->Discard();
			throw;
		}
		catch(const std::exception &ex)
		{
			error("error while submitting urb: ", ex.what());
			urb->Discard();
			throw;
		}
	}

	void Device::WriteBulk(const EndpointPtr & ep, const IObjectInputStreamPtr &inputStream, int timeout)
	{
		Urb urb(*_bufferAllocator, _fd.Get(), USBDEVFS_URB_TYPE_BULK, ep);
		size_t transferSize = urb.GetTransferSize();

		size_t r;
		bool continuation = false;
		do
		{
			r = urb.Send(inputStream, transferSize);

			if (_capabilities & USBDEVFS_CAP_ZERO_PACKET)
				urb.SetZeroPacketFlag(r != transferSize);

			if (_capabilities & USBDEVFS_CAP_BULK_CONTINUATION)
			{
				urb.SetContinuationFlag(continuation);
				continuation = true;
			}
			Submit(&urb, timeout);
		}
		while(r == transferSize);
	}

	void Device::ReadBulk(const EndpointPtr & ep, const IObjectOutputStreamPtr &outputStream, int timeout)
	{
		Urb urb(*_bufferAllocator, _fd.Get(), USBDEVFS_URB_TYPE_BULK, ep);
		size_t transferSize = urb.GetTransferSize();

		size_t r;
		bool continuation = false;
		do
		{
			if (_capabilities & USBDEVFS_CAP_BULK_CONTINUATION)
			{
				urb.SetContinuationFlag(continuation);
				continuation = true;
			}
			Submit(&urb, timeout);

			r = urb.Recv(outputStream);
		}
		while(r == transferSize);
	}

	u8 Device::TransactionType(const EndpointPtr &ep)
	{
		EndpointType type = ep->GetType();
		switch(type)
		{
		case EndpointType::Control:
			return USBDEVFS_URB_TYPE_CONTROL;
		case EndpointType::Isochronous:
			return USBDEVFS_URB_TYPE_ISO;
		case EndpointType::Bulk:
			return USBDEVFS_URB_TYPE_BULK;
		case EndpointType::Interrupt:
			return USBDEVFS_URB_TYPE_INTERRUPT;
		default:
			throw std::runtime_error("invalid endpoint type");
		}
	}

	void Device::ReadControl(u8 type, u8 req, u16 value, u16 index, ByteArray &data, int timeout)
	{
		debug("read control ", hex(type, 2), " ", hex(req, 2), " ", hex(value, 4), " ", hex(index, 4));
		usbdevfs_ctrltransfer ctrl = { };
		ctrl.bRequestType = type;
		ctrl.bRequest = req;
		ctrl.wValue = value;
		ctrl.wIndex = index;
		ctrl.wLength = data.size();
		ctrl.data = const_cast<u8 *>(data.data());
		ctrl.timeout = timeout;

		int fd = _fd.Get();

		int r = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
		if (r >= 0)
			data.resize(r);
		else if (errno == EAGAIN)
			throw TimeoutException("timeout sending control transfer");
		else
			throw posix::Exception("ioctl");
	}

	void Device::WriteControl(u8 type, u8 req, u16 value, u16 index, const ByteArray &data, int timeout)
	{
		debug("write control ", hex(type, 2), " ", hex(req, 2), " ", hex(value, 4), " ", hex(index, 4));
		usbdevfs_ctrltransfer ctrl = { };
		ctrl.bRequestType = type;
		ctrl.bRequest = req;
		ctrl.wValue = value;
		ctrl.wIndex = index;
		ctrl.wLength = data.size();
		ctrl.data = const_cast<u8 *>(data.data());
		ctrl.timeout = timeout;

		int fd = _fd.Get();

		int r = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
		if (r >= 0)
			return;
		else if (errno == EAGAIN)
			throw TimeoutException("timeout sending control transfer");
		else
			throw posix::Exception("ioctl");
	}

}}
<commit_msg>fixed invalid exception message<commit_after>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015-2018  Vladimir Menshakov

    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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <usb/BufferAllocator.h>
#include <usb/Device.h>
#include <Exception.h>
#include <mtp/usb/TimeoutException.h>
#include <mtp/usb/DeviceBusyException.h>
#include <mtp/usb/DeviceNotFoundException.h>
#include <mtp/ByteArray.h>
#include <mtp/log.h>

#include <sys/ioctl.h>
#include <sys/time.h>
#include <poll.h>
#include <signal.h>

#include "linux/usbdevice_fs.h"

#define IOCTL(FD, ...) do \
{ \
	int r = ioctl(FD, __VA_ARGS__); \
	if (r < 0) \
	{ \
		if (errno == EBUSY) \
			throw DeviceBusyException(FD); \
		else if (errno == ENODEV) \
			throw DeviceNotFoundException(); \
		else \
			throw posix::Exception("ioctl(" #__VA_ARGS__ ")"); \
	} \
} while(false)

namespace mtp { namespace usb
{

	InterfaceToken::InterfaceToken(int fd, unsigned interfaceNumber): _fd(fd), _interfaceNumber(interfaceNumber)
	{
		IOCTL(_fd, USBDEVFS_CLAIMINTERFACE, &interfaceNumber);
	}

	InterfaceToken::~InterfaceToken()
	{
		ioctl(_fd, USBDEVFS_RELEASEINTERFACE, &_interfaceNumber);
	}

#define PRINT_CAP(CAP, NAME) \
	if (capabilities & (CAP)) \
	{ \
		debug(NAME " "); \
		capabilities &= ~(CAP); \
	}

	Device::Device(int fd, const EndpointPtr &controlEp): _fd(fd), _capabilities(0), _controlEp(controlEp)
	{
		try
		{ IOCTL(_fd.Get(), USBDEVFS_RESET); }
		catch(const std::exception &ex)
		{ error("resetting device failed: ", ex.what()); }

		try { IOCTL(_fd.Get(), USBDEVFS_GET_CAPABILITIES, &_capabilities); }
		catch(const std::exception &ex)
		{ error("get usbfs capabilities failed: ", ex.what()); }

		debug("capabilities = 0x", hex(_capabilities, 8));
		bool mmap = _capabilities & USBDEVFS_CAP_MMAP;
		//disable mmap allocation for now, see https://github.com/whoozle/android-file-transfer-linux/issues/194
#if 1
		mmap = false;
#endif
		_bufferAllocator = std::make_shared<BufferAllocator>(mmap? fd: -1);

		if (_capabilities)
		{
			u32 capabilities = _capabilities;
			PRINT_CAP(USBDEVFS_CAP_ZERO_PACKET, "<zero-packet>");
			PRINT_CAP(USBDEVFS_CAP_BULK_CONTINUATION, "<bulk-continuation>");
			PRINT_CAP(USBDEVFS_CAP_NO_PACKET_SIZE_LIM, "<no-packet-size-limit>");
			PRINT_CAP(USBDEVFS_CAP_BULK_SCATTER_GATHER, "<bulk-scatter-gather>");
			PRINT_CAP(USBDEVFS_CAP_REAP_AFTER_DISCONNECT, "<reap-after-disconnect>");
			PRINT_CAP(USBDEVFS_CAP_MMAP, "<mmap>");
			PRINT_CAP(USBDEVFS_CAP_DROP_PRIVILEGES, "<drop-privileges>");
			if (capabilities)
				debug("<unknown capability 0x", hex(capabilities, 2), ">");
		}
		else
			debug("[none]\n");
	}

	Device::~Device()
	{ }

	int Device::GetConfiguration() const
	{
		return 0;
	}

	void Device::SetConfiguration(int idx)
	{
		error("SetConfiguration(", idx, "): not implemented");
	}

	struct Device::Urb : usbdevfs_urb, Noncopyable
	{
		static const int 		MaxBufferSize = 4096;
		BufferAllocator &		Allocator;
		int						Fd;
		int						PacketSize;
		Buffer					DataBuffer;

		Urb(BufferAllocator & allocator, int fd, u8 urbType, const EndpointPtr & ep):
			usbdevfs_urb(),
			Allocator(allocator),
			Fd(fd),
			PacketSize(ep->GetMaxPacketSize()),
			DataBuffer(Allocator.Allocate(std::max(PacketSize, MaxBufferSize / PacketSize * PacketSize)))
		{
			type			= urbType;
			endpoint		= ep->GetAddress();
			buffer			= DataBuffer.GetData();
			buffer_length	= DataBuffer.GetSize();
		}

		usbdevfs_urb *GetKernelUrb()
		{ return static_cast<usbdevfs_urb *>(this); }

		~Urb()
		{ Allocator.Free(DataBuffer); }

		size_t GetTransferSize() const
		{ return DataBuffer.GetSize(); }

		void Submit()
		{
			IOCTL(Fd, USBDEVFS_SUBMITURB, GetKernelUrb());
		}

		void Discard()
		{
			int r = ioctl(Fd, USBDEVFS_DISCARDURB, GetKernelUrb());
			if (r != 0)
			{
				perror("ioctl(USBDEVFS_DISCARDURB)");
			}
		}

		size_t Send(const IObjectInputStreamPtr &inputStream, size_t size)
		{
			if (size > DataBuffer.GetSize())
				throw std::logic_error("invalid size passed to Send");
			auto data = DataBuffer.GetData();
			size_t r = inputStream->Read(data, size);
			//HexDump("write", ByteArray(data, data + r), true);
			buffer_length = r;
			return r;
		}

		size_t Send(const ByteArray &inputData)
		{
			size_t r = std::min(DataBuffer.GetSize(), inputData.size());
			std::copy(inputData.data(), inputData.data() + r, DataBuffer.GetData());
			buffer_length = r;
			return r;
		}

		size_t Recv(const IObjectOutputStreamPtr &outputStream)
		{
			auto data = DataBuffer.GetData();
			//HexDump("read", ByteArray(data, data + actual_length), true);
			return outputStream->Write(data, actual_length);
		}

		template<unsigned Flag>
		void SetFlag(bool value)
		{
			if (value)
				flags |= Flag;
			else
				flags &= ~Flag;
		}

		void SetContinuationFlag(bool continuation)
		{ SetFlag<USBDEVFS_URB_BULK_CONTINUATION>(continuation); }

		void SetZeroPacketFlag(bool zero)
		{ SetFlag<USBDEVFS_URB_ZERO_PACKET>(zero); }
	};

	void * Device::Reap(int timeout)
	{
		timeval started = {};
		if (gettimeofday(&started, NULL) == -1)
			throw posix::Exception("gettimeofday");

		pollfd fd = {};
		fd.fd		= _fd.Get();
		fd.events	= POLLOUT | POLLWRNORM;
		int r = poll(&fd, 1, timeout);

		timeval now = {};
		if (gettimeofday(&now, NULL) == -1)
			throw posix::Exception("gettimeofday");

		if (r < 0)
			throw posix::Exception("poll");

		if (r == 0 && timeout > 0)
		{
			int ms = (now.tv_sec - started.tv_sec) * 1000 + (now.tv_usec - started.tv_usec) / 1000;
			error(ms, " ms since the last poll call");
		}
		auto urb = AsyncReap();
		if (urb)
			return urb;
		else
			throw TimeoutException("timeout reaping usb urb");
	}

	void * Device::AsyncReap()
	{
		usbdevfs_urb *urb;
		int r = ioctl(_fd.Get(), USBDEVFS_REAPURBNDELAY, &urb);
		if (r == 0)
			return urb;
		else if (errno == EAGAIN)
			return nullptr;
		else
			throw posix::Exception("ioctl(USBDEVFS_REAPURBNDELAY)");
	}

	void Device::ClearHalt(const EndpointPtr & ep)
	{
		try
		{ unsigned index = ep->GetAddress(); IOCTL(_fd.Get(), USBDEVFS_CLEAR_HALT, &index); }
		catch(const std::exception &ex)
		{ error("clearing halt status for ep ", hex(ep->GetAddress(), 2), ": ", ex.what()); }
	}

	void Device::Submit(Urb *urb, int timeout)
	{
		urb->Submit();
		try
		{
			while(true)
			{
				usbdevfs_urb * completedKernelUrb = static_cast<usbdevfs_urb *>(Reap(timeout));
				if (urb->GetKernelUrb() != completedKernelUrb)
				{
					error("got unknown urb: ", completedKernelUrb);
					continue;
				}
				else
					break;
			}
		}
		catch(const TimeoutException &ex)
		{
			urb->Discard();
			throw;
		}
		catch(const std::exception &ex)
		{
			error("error while submitting urb: ", ex.what());
			urb->Discard();
			throw;
		}
	}

	void Device::WriteBulk(const EndpointPtr & ep, const IObjectInputStreamPtr &inputStream, int timeout)
	{
		Urb urb(*_bufferAllocator, _fd.Get(), USBDEVFS_URB_TYPE_BULK, ep);
		size_t transferSize = urb.GetTransferSize();

		size_t r;
		bool continuation = false;
		do
		{
			r = urb.Send(inputStream, transferSize);

			if (_capabilities & USBDEVFS_CAP_ZERO_PACKET)
				urb.SetZeroPacketFlag(r != transferSize);

			if (_capabilities & USBDEVFS_CAP_BULK_CONTINUATION)
			{
				urb.SetContinuationFlag(continuation);
				continuation = true;
			}
			Submit(&urb, timeout);
		}
		while(r == transferSize);
	}

	void Device::ReadBulk(const EndpointPtr & ep, const IObjectOutputStreamPtr &outputStream, int timeout)
	{
		Urb urb(*_bufferAllocator, _fd.Get(), USBDEVFS_URB_TYPE_BULK, ep);
		size_t transferSize = urb.GetTransferSize();

		size_t r;
		bool continuation = false;
		do
		{
			if (_capabilities & USBDEVFS_CAP_BULK_CONTINUATION)
			{
				urb.SetContinuationFlag(continuation);
				continuation = true;
			}
			Submit(&urb, timeout);

			r = urb.Recv(outputStream);
		}
		while(r == transferSize);
	}

	u8 Device::TransactionType(const EndpointPtr &ep)
	{
		EndpointType type = ep->GetType();
		switch(type)
		{
		case EndpointType::Control:
			return USBDEVFS_URB_TYPE_CONTROL;
		case EndpointType::Isochronous:
			return USBDEVFS_URB_TYPE_ISO;
		case EndpointType::Bulk:
			return USBDEVFS_URB_TYPE_BULK;
		case EndpointType::Interrupt:
			return USBDEVFS_URB_TYPE_INTERRUPT;
		default:
			throw std::runtime_error("invalid endpoint type");
		}
	}

	void Device::ReadControl(u8 type, u8 req, u16 value, u16 index, ByteArray &data, int timeout)
	{
		debug("read control ", hex(type, 2), " ", hex(req, 2), " ", hex(value, 4), " ", hex(index, 4));
		usbdevfs_ctrltransfer ctrl = { };
		ctrl.bRequestType = type;
		ctrl.bRequest = req;
		ctrl.wValue = value;
		ctrl.wIndex = index;
		ctrl.wLength = data.size();
		ctrl.data = const_cast<u8 *>(data.data());
		ctrl.timeout = timeout;

		int fd = _fd.Get();

		int r = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
		if (r >= 0)
			data.resize(r);
		else if (errno == EAGAIN)
			throw TimeoutException("timeout sending control transfer");
		else
			throw posix::Exception("ioctl");
	}

	void Device::WriteControl(u8 type, u8 req, u16 value, u16 index, const ByteArray &data, int timeout)
	{
		debug("write control ", hex(type, 2), " ", hex(req, 2), " ", hex(value, 4), " ", hex(index, 4));
		usbdevfs_ctrltransfer ctrl = { };
		ctrl.bRequestType = type;
		ctrl.bRequest = req;
		ctrl.wValue = value;
		ctrl.wIndex = index;
		ctrl.wLength = data.size();
		ctrl.data = const_cast<u8 *>(data.data());
		ctrl.timeout = timeout;

		int fd = _fd.Get();

		int r = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
		if (r >= 0)
			return;
		else if (errno == EAGAIN)
			throw TimeoutException("timeout sending control transfer");
		else
			throw posix::Exception("ioctl");
	}

}}
<|endoftext|>


<commit_before>//TODO: when using many nonterminals, group passive edges for a span (treat all as a single X for the active items).

//TODO: figure out what cdyer was talking about when he said that having unary rules A->B and B->A, doesn't make cycles appear in result provided rules are sorted in some way (that they typically are)

#include "bottom_up_parser.h"

#include <iostream>
#include <map>

#include "hg.h"
#include "array2d.h"
#include "tdict.h"
#include "verbose.h"

using namespace std;

class ActiveChart;
class PassiveChart {
 public:
  PassiveChart(const string& goal,
               const vector<GrammarPtr>& grammars,
               const Lattice& input,
               Hypergraph* forest);
  ~PassiveChart();

  inline const vector<int>& operator()(int i, int j) const { return chart_(i,j); }
  bool Parse();
  inline int size() const { return chart_.width(); }
  inline bool GoalFound() const { return goal_idx_ >= 0; }
  inline int GetGoalIndex() const { return goal_idx_; }

 private:
  void ApplyRules(const int i,
                  const int j,
                  const RuleBin* rules,
                  const Hypergraph::TailNodeVector& tail,
                  const float lattice_cost);

  void ApplyRule(const int i,
                 const int j,
                 const TRulePtr& r,
                 const Hypergraph::TailNodeVector& ant_nodes,
                 const float lattice_cost);

  void ApplyUnaryRules(const int i, const int j);

  const vector<GrammarPtr>& grammars_;
  const Lattice& input_;
  Hypergraph* forest_;
  Array2D<vector<int> > chart_;   // chart_(i,j) is the list of nodes derived spanning i,j
  typedef map<int, int> Cat2NodeMap;
  Array2D<Cat2NodeMap> nodemap_;
  vector<ActiveChart*> act_chart_;
  const WordID goal_cat_;    // category that is being searched for at [0,n]
  TRulePtr goal_rule_;
  int goal_idx_;             // index of goal node, if found
  const int lc_fid_;

  static WordID kGOAL;       // [Goal]
};

WordID PassiveChart::kGOAL = 0;

class ActiveChart {
 public:
  ActiveChart(const Hypergraph* hg, const PassiveChart& psv_chart) :
    hg_(hg),
    act_chart_(psv_chart.size(), psv_chart.size()), psv_chart_(psv_chart) {}

  struct ActiveItem {
    ActiveItem(const GrammarIter* g, const Hypergraph::TailNodeVector& a, float lcost) :
      gptr_(g), ant_nodes_(a), lattice_cost(lcost) {}
    explicit ActiveItem(const GrammarIter* g) :
      gptr_(g), ant_nodes_(), lattice_cost(0.0) {}

    void ExtendTerminal(int symbol, float src_cost, vector<ActiveItem>* out_cell) const {
      const GrammarIter* ni = gptr_->Extend(symbol);
      if (ni) {
        out_cell->push_back(ActiveItem(ni, ant_nodes_, lattice_cost + src_cost));
      }
    }
    void ExtendNonTerminal(const Hypergraph* hg, int node_index, vector<ActiveItem>* out_cell) const {
      int symbol = hg->nodes_[node_index].cat_;
      const GrammarIter* ni = gptr_->Extend(symbol);
      if (!ni) return;
      Hypergraph::TailNodeVector na(ant_nodes_.size() + 1);
      for (int i = 0; i < ant_nodes_.size(); ++i)
        na[i] = ant_nodes_[i];
      na[ant_nodes_.size()] = node_index;
      out_cell->push_back(ActiveItem(ni, na, lattice_cost));
    }

    const GrammarIter* gptr_;
    Hypergraph::TailNodeVector ant_nodes_;
    float lattice_cost;  // TODO? use SparseVector<double>
  };

  inline const vector<ActiveItem>& operator()(int i, int j) const { return act_chart_(i,j); }
  void SeedActiveChart(const Grammar& g) {
    int size = act_chart_.width();
    for (int i = 0; i < size; ++i)
      if (g.HasRuleForSpan(i,i,0))
        act_chart_(i,i).push_back(ActiveItem(g.GetRoot()));
  }

  void ExtendActiveItems(int i, int k, int j) {
    //cerr << "  LOOK(" << i << "," << k << ") for completed items in (" << k << "," << j << ")\n";
    vector<ActiveItem>& cell = act_chart_(i,j);
    const vector<ActiveItem>& icell = act_chart_(i,k);
    const vector<int>& idxs = psv_chart_(k, j);
    //if (!idxs.empty()) { cerr << "FOUND IN (" << k << "," << j << ")\n"; }
    for (vector<ActiveItem>::const_iterator di = icell.begin(); di != icell.end(); ++di) {
      for (vector<int>::const_iterator ni = idxs.begin(); ni != idxs.end(); ++ni) {
         di->ExtendNonTerminal(hg_, *ni, &cell);
      }
    }
  }

  void AdvanceDotsForAllItemsInCell(int i, int j, const vector<vector<LatticeArc> >& input) {
    //cerr << "ADVANCE(" << i << "," << j << ")\n";
    for (int k=i+1; k < j; ++k)
      ExtendActiveItems(i, k, j);

    const vector<LatticeArc>& out_arcs = input[j-1];
    for (vector<LatticeArc>::const_iterator ai = out_arcs.begin();
         ai != out_arcs.end(); ++ai) {
      const WordID& f = ai->label;
      const double& c = ai->cost;
      const int& len = ai->dist2next;
      //VLOG(1) << "F: " << TD::Convert(f) << endl;
      const vector<ActiveItem>& ec = act_chart_(i, j-1);
      for (vector<ActiveItem>::const_iterator di = ec.begin(); di != ec.end(); ++di)
        di->ExtendTerminal(f, c, &act_chart_(i, j + len - 1));
    }
  }

 private:
  const Hypergraph* hg_;
  Array2D<vector<ActiveItem> > act_chart_;
  const PassiveChart& psv_chart_;
};

PassiveChart::PassiveChart(const string& goal,
                           const vector<GrammarPtr>& grammars,
                           const Lattice& input,
                           Hypergraph* forest) :
    grammars_(grammars),
    input_(input),
    forest_(forest),
    chart_(input.size()+1, input.size()+1),
    nodemap_(input.size()+1, input.size()+1),
    goal_cat_(TD::Convert(goal) * -1),
    goal_rule_(new TRule("[Goal] ||| [" + goal + ",1] ||| [" + goal + ",1]")),
    goal_idx_(-1),
    lc_fid_(FD::Convert("LatticeCost")) {
  act_chart_.resize(grammars_.size());
  for (int i = 0; i < grammars_.size(); ++i)
    act_chart_[i] = new ActiveChart(forest, *this);
  if (!kGOAL) kGOAL = TD::Convert("Goal") * -1;
  if (!SILENT) cerr << "  Goal category: [" << goal << ']' << endl;
}

void PassiveChart::ApplyRule(const int i,
                             const int j,
                             const TRulePtr& r,
                             const Hypergraph::TailNodeVector& ant_nodes,
                             const float lattice_cost) {
  Hypergraph::Edge* new_edge = forest_->AddEdge(r, ant_nodes);
  new_edge->prev_i_ = r->prev_i;
  new_edge->prev_j_ = r->prev_j;
  new_edge->i_ = i;
  new_edge->j_ = j;
  new_edge->feature_values_ = r->GetFeatureValues();
  if (lattice_cost && lc_fid_)
    new_edge->feature_values_.set_value(lc_fid_, lattice_cost);
  Cat2NodeMap& c2n = nodemap_(i,j);
  const bool is_goal = (r->GetLHS() == kGOAL);
  const Cat2NodeMap::iterator ni = c2n.find(r->GetLHS());
  Hypergraph::Node* node = NULL;
  if (ni == c2n.end()) {
    node = forest_->AddNode(r->GetLHS());
    c2n[r->GetLHS()] = node->id_;
    if (is_goal) {
      assert(goal_idx_ == -1);
      goal_idx_ = node->id_;
    } else {
      chart_(i,j).push_back(node->id_);
    }
  } else {
    node = &forest_->nodes_[ni->second];
  }
  forest_->ConnectEdgeToHeadNode(new_edge, node);
}

void PassiveChart::ApplyRules(const int i,
                       const int j,
                       const RuleBin* rules,
                       const Hypergraph::TailNodeVector& tail,
                       const float lattice_cost) {
  const int n = rules->GetNumRules();
  for (int k = 0; k < n; ++k)
    ApplyRule(i, j, rules->GetIthRule(k), tail, lattice_cost);
}

void PassiveChart::ApplyUnaryRules(const int i, const int j) {
  const vector<int>& nodes = chart_(i,j);  // reference is important!
  for (int gi = 0; gi < grammars_.size(); ++gi) {
    if (!grammars_[gi]->HasRuleForSpan(i,j,input_.Distance(i,j))) continue;
    for (int di = 0; di < nodes.size(); ++di) {
      const WordID& cat = forest_->nodes_[nodes[di]].cat_;
      const vector<TRulePtr>& unaries = grammars_[gi]->GetUnaryRulesForRHS(cat);
      for (int ri = 0; ri < unaries.size(); ++ri) {
        // cerr << "At (" << i << "," << j << "): applying " << unaries[ri]->AsString() << endl;
        const Hypergraph::TailNodeVector ant(1, nodes[di]);
        ApplyRule(i, j, unaries[ri], ant, 0);  // may update nodes
      }
    }
  }
}

bool PassiveChart::Parse() {
  size_t in_size_2 = input_.size() * input_.size();
  forest_->nodes_.reserve(in_size_2 * 2);
  size_t res = min(2000000ul, in_size_2 * 1000);
  forest_->edges_.reserve(res);
  goal_idx_ = -1;
  for (int gi = 0; gi < grammars_.size(); ++gi)
    act_chart_[gi]->SeedActiveChart(*grammars_[gi]);

  if (!SILENT) cerr << "    ";
  for (int l=1; l<input_.size()+1; ++l) {
    if (!SILENT) cerr << '.';
    for (int i=0; i<input_.size() + 1 - l; ++i) {
      int j = i + l;
      for (int gi = 0; gi < grammars_.size(); ++gi) {
        const Grammar& g = *grammars_[gi];
        if (g.HasRuleForSpan(i, j, input_.Distance(i, j))) {
          act_chart_[gi]->AdvanceDotsForAllItemsInCell(i, j, input_);

          const vector<ActiveChart::ActiveItem>& cell = (*act_chart_[gi])(i,j);
          for (vector<ActiveChart::ActiveItem>::const_iterator ai = cell.begin();
               ai != cell.end(); ++ai) {
            const RuleBin* rules = (ai->gptr_->GetRules());
            if (!rules) continue;
            ApplyRules(i, j, rules, ai->ant_nodes_, ai->lattice_cost);
          }
        }
      }
      ApplyUnaryRules(i,j);

      for (int gi = 0; gi < grammars_.size(); ++gi) {
        const Grammar& g = *grammars_[gi];
          // deal with non-terminals that were just proved
          if (g.HasRuleForSpan(i, j, input_.Distance(i,j)))
            act_chart_[gi]->ExtendActiveItems(i, i, j);
      }
    }
    const vector<int>& dh = chart_(0, input_.size());
    for (int di = 0; di < dh.size(); ++di) {
      const Hypergraph::Node& node = forest_->nodes_[dh[di]];
      if (node.cat_ == goal_cat_) {
        Hypergraph::TailNodeVector ant(1, node.id_);
        ApplyRule(0, input_.size(), goal_rule_, ant, 0);
      }
    }
  }
  if (!SILENT) cerr << endl;

  if (GoalFound())
    forest_->PruneUnreachable(forest_->nodes_.size() - 1);
  return GoalFound();
}

PassiveChart::~PassiveChart() {
  for (int i = 0; i < act_chart_.size(); ++i)
    delete act_chart_[i];
}

ExhaustiveBottomUpParser::ExhaustiveBottomUpParser(
    const string& goal_sym,
    const vector<GrammarPtr>& grammars) :
  goal_sym_(goal_sym),
  grammars_(grammars) {}

bool ExhaustiveBottomUpParser::Parse(const Lattice& input,
                                     Hypergraph* forest) const {
  PassiveChart chart(goal_sym_, grammars_, input, forest);
  const bool result = chart.Parse();
  return result;
}
<commit_msg>fix compile error on certain gcc's<commit_after>//TODO: when using many nonterminals, group passive edges for a span (treat all as a single X for the active items).

//TODO: figure out what cdyer was talking about when he said that having unary rules A->B and B->A, doesn't make cycles appear in result provided rules are sorted in some way (that they typically are)

#include "bottom_up_parser.h"

#include <iostream>
#include <map>

#include "hg.h"
#include "array2d.h"
#include "tdict.h"
#include "verbose.h"

using namespace std;

class ActiveChart;
class PassiveChart {
 public:
  PassiveChart(const string& goal,
               const vector<GrammarPtr>& grammars,
               const Lattice& input,
               Hypergraph* forest);
  ~PassiveChart();

  inline const vector<int>& operator()(int i, int j) const { return chart_(i,j); }
  bool Parse();
  inline int size() const { return chart_.width(); }
  inline bool GoalFound() const { return goal_idx_ >= 0; }
  inline int GetGoalIndex() const { return goal_idx_; }

 private:
  void ApplyRules(const int i,
                  const int j,
                  const RuleBin* rules,
                  const Hypergraph::TailNodeVector& tail,
                  const float lattice_cost);

  void ApplyRule(const int i,
                 const int j,
                 const TRulePtr& r,
                 const Hypergraph::TailNodeVector& ant_nodes,
                 const float lattice_cost);

  void ApplyUnaryRules(const int i, const int j);

  const vector<GrammarPtr>& grammars_;
  const Lattice& input_;
  Hypergraph* forest_;
  Array2D<vector<int> > chart_;   // chart_(i,j) is the list of nodes derived spanning i,j
  typedef map<int, int> Cat2NodeMap;
  Array2D<Cat2NodeMap> nodemap_;
  vector<ActiveChart*> act_chart_;
  const WordID goal_cat_;    // category that is being searched for at [0,n]
  TRulePtr goal_rule_;
  int goal_idx_;             // index of goal node, if found
  const int lc_fid_;

  static WordID kGOAL;       // [Goal]
};

WordID PassiveChart::kGOAL = 0;

class ActiveChart {
 public:
  ActiveChart(const Hypergraph* hg, const PassiveChart& psv_chart) :
    hg_(hg),
    act_chart_(psv_chart.size(), psv_chart.size()), psv_chart_(psv_chart) {}

  struct ActiveItem {
    ActiveItem(const GrammarIter* g, const Hypergraph::TailNodeVector& a, float lcost) :
      gptr_(g), ant_nodes_(a), lattice_cost(lcost) {}
    explicit ActiveItem(const GrammarIter* g) :
      gptr_(g), ant_nodes_(), lattice_cost(0.0) {}

    void ExtendTerminal(int symbol, float src_cost, vector<ActiveItem>* out_cell) const {
      const GrammarIter* ni = gptr_->Extend(symbol);
      if (ni) {
        out_cell->push_back(ActiveItem(ni, ant_nodes_, lattice_cost + src_cost));
      }
    }
    void ExtendNonTerminal(const Hypergraph* hg, int node_index, vector<ActiveItem>* out_cell) const {
      int symbol = hg->nodes_[node_index].cat_;
      const GrammarIter* ni = gptr_->Extend(symbol);
      if (!ni) return;
      Hypergraph::TailNodeVector na(ant_nodes_.size() + 1);
      for (int i = 0; i < ant_nodes_.size(); ++i)
        na[i] = ant_nodes_[i];
      na[ant_nodes_.size()] = node_index;
      out_cell->push_back(ActiveItem(ni, na, lattice_cost));
    }

    const GrammarIter* gptr_;
    Hypergraph::TailNodeVector ant_nodes_;
    float lattice_cost;  // TODO? use SparseVector<double>
  };

  inline const vector<ActiveItem>& operator()(int i, int j) const { return act_chart_(i,j); }
  void SeedActiveChart(const Grammar& g) {
    int size = act_chart_.width();
    for (int i = 0; i < size; ++i)
      if (g.HasRuleForSpan(i,i,0))
        act_chart_(i,i).push_back(ActiveItem(g.GetRoot()));
  }

  void ExtendActiveItems(int i, int k, int j) {
    //cerr << "  LOOK(" << i << "," << k << ") for completed items in (" << k << "," << j << ")\n";
    vector<ActiveItem>& cell = act_chart_(i,j);
    const vector<ActiveItem>& icell = act_chart_(i,k);
    const vector<int>& idxs = psv_chart_(k, j);
    //if (!idxs.empty()) { cerr << "FOUND IN (" << k << "," << j << ")\n"; }
    for (vector<ActiveItem>::const_iterator di = icell.begin(); di != icell.end(); ++di) {
      for (vector<int>::const_iterator ni = idxs.begin(); ni != idxs.end(); ++ni) {
         di->ExtendNonTerminal(hg_, *ni, &cell);
      }
    }
  }

  void AdvanceDotsForAllItemsInCell(int i, int j, const vector<vector<LatticeArc> >& input) {
    //cerr << "ADVANCE(" << i << "," << j << ")\n";
    for (int k=i+1; k < j; ++k)
      ExtendActiveItems(i, k, j);

    const vector<LatticeArc>& out_arcs = input[j-1];
    for (vector<LatticeArc>::const_iterator ai = out_arcs.begin();
         ai != out_arcs.end(); ++ai) {
      const WordID& f = ai->label;
      const double& c = ai->cost;
      const int& len = ai->dist2next;
      //VLOG(1) << "F: " << TD::Convert(f) << endl;
      const vector<ActiveItem>& ec = act_chart_(i, j-1);
      for (vector<ActiveItem>::const_iterator di = ec.begin(); di != ec.end(); ++di)
        di->ExtendTerminal(f, c, &act_chart_(i, j + len - 1));
    }
  }

 private:
  const Hypergraph* hg_;
  Array2D<vector<ActiveItem> > act_chart_;
  const PassiveChart& psv_chart_;
};

PassiveChart::PassiveChart(const string& goal,
                           const vector<GrammarPtr>& grammars,
                           const Lattice& input,
                           Hypergraph* forest) :
    grammars_(grammars),
    input_(input),
    forest_(forest),
    chart_(input.size()+1, input.size()+1),
    nodemap_(input.size()+1, input.size()+1),
    goal_cat_(TD::Convert(goal) * -1),
    goal_rule_(new TRule("[Goal] ||| [" + goal + ",1] ||| [" + goal + ",1]")),
    goal_idx_(-1),
    lc_fid_(FD::Convert("LatticeCost")) {
  act_chart_.resize(grammars_.size());
  for (int i = 0; i < grammars_.size(); ++i)
    act_chart_[i] = new ActiveChart(forest, *this);
  if (!kGOAL) kGOAL = TD::Convert("Goal") * -1;
  if (!SILENT) cerr << "  Goal category: [" << goal << ']' << endl;
}

void PassiveChart::ApplyRule(const int i,
                             const int j,
                             const TRulePtr& r,
                             const Hypergraph::TailNodeVector& ant_nodes,
                             const float lattice_cost) {
  Hypergraph::Edge* new_edge = forest_->AddEdge(r, ant_nodes);
  new_edge->prev_i_ = r->prev_i;
  new_edge->prev_j_ = r->prev_j;
  new_edge->i_ = i;
  new_edge->j_ = j;
  new_edge->feature_values_ = r->GetFeatureValues();
  if (lattice_cost && lc_fid_)
    new_edge->feature_values_.set_value(lc_fid_, lattice_cost);
  Cat2NodeMap& c2n = nodemap_(i,j);
  const bool is_goal = (r->GetLHS() == kGOAL);
  const Cat2NodeMap::iterator ni = c2n.find(r->GetLHS());
  Hypergraph::Node* node = NULL;
  if (ni == c2n.end()) {
    node = forest_->AddNode(r->GetLHS());
    c2n[r->GetLHS()] = node->id_;
    if (is_goal) {
      assert(goal_idx_ == -1);
      goal_idx_ = node->id_;
    } else {
      chart_(i,j).push_back(node->id_);
    }
  } else {
    node = &forest_->nodes_[ni->second];
  }
  forest_->ConnectEdgeToHeadNode(new_edge, node);
}

void PassiveChart::ApplyRules(const int i,
                       const int j,
                       const RuleBin* rules,
                       const Hypergraph::TailNodeVector& tail,
                       const float lattice_cost) {
  const int n = rules->GetNumRules();
  for (int k = 0; k < n; ++k)
    ApplyRule(i, j, rules->GetIthRule(k), tail, lattice_cost);
}

void PassiveChart::ApplyUnaryRules(const int i, const int j) {
  const vector<int>& nodes = chart_(i,j);  // reference is important!
  for (int gi = 0; gi < grammars_.size(); ++gi) {
    if (!grammars_[gi]->HasRuleForSpan(i,j,input_.Distance(i,j))) continue;
    for (int di = 0; di < nodes.size(); ++di) {
      const WordID& cat = forest_->nodes_[nodes[di]].cat_;
      const vector<TRulePtr>& unaries = grammars_[gi]->GetUnaryRulesForRHS(cat);
      for (int ri = 0; ri < unaries.size(); ++ri) {
        // cerr << "At (" << i << "," << j << "): applying " << unaries[ri]->AsString() << endl;
        const Hypergraph::TailNodeVector ant(1, nodes[di]);
        ApplyRule(i, j, unaries[ri], ant, 0);  // may update nodes
      }
    }
  }
}

bool PassiveChart::Parse() {
  size_t in_size_2 = input_.size() * input_.size();
  forest_->nodes_.reserve(in_size_2 * 2);
  size_t res = min(static_cast<size_t>(2000000), static_cast<size_t>(in_size_2 * 1000));
  forest_->edges_.reserve(res);
  goal_idx_ = -1;
  for (int gi = 0; gi < grammars_.size(); ++gi)
    act_chart_[gi]->SeedActiveChart(*grammars_[gi]);

  if (!SILENT) cerr << "    ";
  for (int l=1; l<input_.size()+1; ++l) {
    if (!SILENT) cerr << '.';
    for (int i=0; i<input_.size() + 1 - l; ++i) {
      int j = i + l;
      for (int gi = 0; gi < grammars_.size(); ++gi) {
        const Grammar& g = *grammars_[gi];
        if (g.HasRuleForSpan(i, j, input_.Distance(i, j))) {
          act_chart_[gi]->AdvanceDotsForAllItemsInCell(i, j, input_);

          const vector<ActiveChart::ActiveItem>& cell = (*act_chart_[gi])(i,j);
          for (vector<ActiveChart::ActiveItem>::const_iterator ai = cell.begin();
               ai != cell.end(); ++ai) {
            const RuleBin* rules = (ai->gptr_->GetRules());
            if (!rules) continue;
            ApplyRules(i, j, rules, ai->ant_nodes_, ai->lattice_cost);
          }
        }
      }
      ApplyUnaryRules(i,j);

      for (int gi = 0; gi < grammars_.size(); ++gi) {
        const Grammar& g = *grammars_[gi];
          // deal with non-terminals that were just proved
          if (g.HasRuleForSpan(i, j, input_.Distance(i,j)))
            act_chart_[gi]->ExtendActiveItems(i, i, j);
      }
    }
    const vector<int>& dh = chart_(0, input_.size());
    for (int di = 0; di < dh.size(); ++di) {
      const Hypergraph::Node& node = forest_->nodes_[dh[di]];
      if (node.cat_ == goal_cat_) {
        Hypergraph::TailNodeVector ant(1, node.id_);
        ApplyRule(0, input_.size(), goal_rule_, ant, 0);
      }
    }
  }
  if (!SILENT) cerr << endl;

  if (GoalFound())
    forest_->PruneUnreachable(forest_->nodes_.size() - 1);
  return GoalFound();
}

PassiveChart::~PassiveChart() {
  for (int i = 0; i < act_chart_.size(); ++i)
    delete act_chart_[i];
}

ExhaustiveBottomUpParser::ExhaustiveBottomUpParser(
    const string& goal_sym,
    const vector<GrammarPtr>& grammars) :
  goal_sym_(goal_sym),
  grammars_(grammars) {}

bool ExhaustiveBottomUpParser::Parse(const Lattice& input,
                                     Hypergraph* forest) const {
  PassiveChart chart(goal_sym_, grammars_, input, forest);
  const bool result = chart.Parse();
  return result;
}
<|endoftext|>


<commit_before>#include "client.hpp"
#include "ircd.hpp"
#include "tokens.hpp"
#include "modes.hpp"

void Client::send_motd()
{
  send(RPL_MOTDSTART, ":- " + server.name() + " Message of the day - ");
  const std::string& motd = server.get_motd();
  size_t prev = 0;
  size_t next = motd.find("\n");
  char buffer[256];

  while (next != motd.npos)
  {
    int len = snprintf(buffer, sizeof(buffer),
        ":%s 372 %s :%.*s\r\n",
        server.name().c_str(), nick().c_str(), next-prev, &motd[prev]);
    if (len > 0) send_raw(buffer, len);
    prev = next + 1;
    next = motd.find("\n", prev);
  }
  int len = snprintf(buffer, sizeof(buffer),
      ":%s 372 %s :%s\r\n",
      server.name().c_str(), nick().c_str(), &motd[prev]);
  if (len > 0) send_raw(buffer, len);
  send(RPL_ENDOFMOTD, ":End of MOTD command");
}

void Client::send_lusers()
{
  send(RPL_LUSERCLIENT, ":There are " + std::to_string(server.get_counter(STAT_TOTAL_USERS)) +
                        " users and 0 services on 1 servers");
  send(RPL_LUSEROP,       std::to_string(server.get_counter(STAT_OPERATORS)) + " :operator(s) online");
  send(RPL_LUSERCHANNELS, std::to_string(server.get_counter(STAT_CHANNELS)) + " :channels formed");
  send(RPL_LUSERME, ":I have " + std::to_string(server.get_counter(STAT_LOCAL_USERS)) + " clients and 1 servers");

  std::string mu = std::to_string(server.get_counter(STAT_MAX_USERS));
  std::string tc = std::to_string(server.get_counter(STAT_TOTAL_CONNS));
  send(250, "Highest connection count: " + mu + " (" + mu + " clients) (" + tc + " connections received)");
}

void Client::send_modes()
{
  char data[128];
  int len = snprintf(data, sizeof(data),
    ":%s MODE %s +%s\r\n", nickuserhost().c_str(), nick().c_str(), mode_string().c_str());

  send_raw(data, len);
}

void Client::send_stats(const std::string& stat)
{
  char buffer[128];
  int  len;

  if (stat == "u")
  {
    static const int DAY = 3600 * 24;

    auto uptime = server.uptime();
    int days = uptime / DAY;
    uptime -= days * DAY;
    int hours = uptime / 3600;
    uptime -= hours * 3600;
    int mins = uptime / 60;
    int secs = uptime % 60;

    len = snprintf(buffer, sizeof(buffer),
          ":%s %03u %s :Server has been up %d days %d hours, %d minutes and %d seconds\r\n",
          server.name().c_str(), RPL_STATSUPTIME, nick().c_str(), days, hours, mins, secs);
  }
  else if (stat == "m")
  {
    len = snprintf(buffer, sizeof(buffer),
          ":%s %03u %s :Heap usage: %.3f mb\r\n",
          server.name().c_str(), 244, nick().c_str(), OS::heap_usage() / 1024.f / 1024.f);
  }
  else {
    len = snprintf(buffer, sizeof(buffer),
          ":%s %03u %s :No such statistic\r\n",
          server.name().c_str(), 249, nick().c_str());
  }
  send_raw(buffer, len);
}
<commit_msg>Increase MOTD throughput<commit_after>#include "client.hpp"
#include "ircd.hpp"
#include "tokens.hpp"
#include "modes.hpp"

void Client::send_motd()
{
  char     buffer[2048];
  uint16_t total = 0;
  // motd start
  int len = sprintf(buffer, ":%s 375 %s :- %s Message of the day\r\n",
      server.name().c_str(), nick().c_str(), server.name().c_str());
  total += len;
  // motd contents
  const std::string& motd = server.get_motd();
  size_t prev = 0;
  size_t next = motd.find("\n");

  while (next != motd.npos)
  {
    len = snprintf(buffer + total, sizeof(buffer) - total,
        ":%s 372 %s :%.*s\r\n",
        server.name().c_str(), nick().c_str(), next-prev, &motd[prev]);
    total += len;
    prev = next + 1;
    next = motd.find("\n", prev);
  }
  // last line of motd
  len = snprintf(buffer + total, sizeof(buffer) - total,
      ":%s 372 %s :%s\r\n",
      server.name().c_str(), nick().c_str(), &motd[prev]);
  total += len;
  // end of motd
  len = snprintf(buffer + total, sizeof(buffer) - total,
      ":%s 376 %s :End of MOTD command\r\n",
      server.name().c_str(), nick().c_str());
  total += len;
  send_raw(buffer, total);
}

void Client::send_lusers()
{
  send(RPL_LUSERCLIENT, ":There are " + std::to_string(server.get_counter(STAT_TOTAL_USERS)) +
                        " users and 0 services on 1 servers");
  send(RPL_LUSEROP,       std::to_string(server.get_counter(STAT_OPERATORS)) + " :operator(s) online");
  send(RPL_LUSERCHANNELS, std::to_string(server.get_counter(STAT_CHANNELS)) + " :channels formed");
  send(RPL_LUSERME, ":I have " + std::to_string(server.get_counter(STAT_LOCAL_USERS)) + " clients and 1 servers");

  std::string mu = std::to_string(server.get_counter(STAT_MAX_USERS));
  std::string tc = std::to_string(server.get_counter(STAT_TOTAL_CONNS));
  send(250, "Highest connection count: " + mu + " (" + mu + " clients) (" + tc + " connections received)");
}

void Client::send_modes()
{
  char data[128];
  int len = snprintf(data, sizeof(data),
    ":%s MODE %s +%s\r\n", nickuserhost().c_str(), nick().c_str(), mode_string().c_str());

  send_raw(data, len);
}

void Client::send_stats(const std::string& stat)
{
  char buffer[128];
  int  len;

  if (stat == "u")
  {
    static const int DAY = 3600 * 24;

    auto uptime = server.uptime();
    int days = uptime / DAY;
    uptime -= days * DAY;
    int hours = uptime / 3600;
    uptime -= hours * 3600;
    int mins = uptime / 60;
    int secs = uptime % 60;

    len = snprintf(buffer, sizeof(buffer),
          ":%s %03u %s :Server has been up %d days %d hours, %d minutes and %d seconds\r\n",
          server.name().c_str(), RPL_STATSUPTIME, nick().c_str(), days, hours, mins, secs);
  }
  else if (stat == "m")
  {
    len = snprintf(buffer, sizeof(buffer),
          ":%s %03u %s :Heap usage: %.3f mb\r\n",
          server.name().c_str(), 244, nick().c_str(), OS::heap_usage() / 1024.f / 1024.f);
  }
  else {
    len = snprintf(buffer, sizeof(buffer),
          ":%s %03u %s :No such statistic\r\n",
          server.name().c_str(), 249, nick().c_str());
  }
  send_raw(buffer, len);
}
<|endoftext|>


<commit_before><commit_msg>[asan] Fix new[]/delete mismatch in tests.<commit_after><|endoftext|>