<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(STLHELPERS_HEADER_GUARD_1357924680)
#define STLHELPERS_HEADER_GUARD_1357924680

// Base include file.  Must be first.
#include <Include/PlatformDefinitions.hpp>

#include <algorithm>
#include <functional>

/**
 * Functor to delete objects, used in STL iteration algorithms.
 */
template <class T>
#if defined(XALAN_NO_NAMESPACES)
struct DeleteFunctor : public unary_function<const T*, void>
#else
struct DeleteFunctor : public std::unary_function<const T*, void>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<const T*, void>	BaseClassType;
#else
	typedef std::unary_function<const T*, void>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	/**
	 * Delete the object pointed to by argument.
	 *
	 * @param thePointer pointer to object to be deleted
	 */
	result_type
	operator()(argument_type	thePointer) const
	{
#if defined(XALAN_CANNOT_DELETE_CONST)
		delete (T*)thePointer;
#else
		delete thePointer;
#endif
	}
};

#if !defined(XALAN_SGI_BASED_STL)

/**
 * Functor to retrieve the key of a key-value pair in a map, used in STL
 * iteration algorithms.
 */
template <class PairType>
#if defined(XALAN_NO_NAMESPACES)
struct select1st : public unary_function<PairType, PairType::first_type>
#else
struct select1st : public std::unary_function<PairType, PairType::first_type>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<PairType, PairType::first_type>	BaseClassType;
#else
	typedef std::unary_function<PairType, PairType::first_type>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	typedef PairType								value_type;

	/**
	 * Retrieve the key of a key-value pair.
	 *
	 * @param thePair key-value pair
	 * @return key
	 */
	result_type
	operator()(const argument_type&		thePair) const
	{
		return thePair.first;
	}
};

/**
 * Functor to retrieve the value of a key-value pair in a map, used in STL
 * iteration algorithms.
 */
template <class PairType>
#if defined(XALAN_NO_NAMESPACES)
struct select2nd : public unary_function<PairType, PairType::second_type>
#else
struct select2nd : public std::unary_function<PairType, PairType::second_type>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<PairType, PairType::second_type>	BaseClassType;
#else
	typedef std::unary_function<PairType, PairType::second_type>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	typedef PairType								value_type;

	/**
	 * Retrieve the value of a key-value pair.
	 *
	 * @param thePair key-value pair
	 * @return value
	 */
	result_type
	operator()(const argument_type&		thePair) const
	{
		return thePair.second;
	}
};

#endif

/**
 * Functor to delete value objects in maps, used in STL iteration algorithms.
 */
template <class T>
#if defined(XALAN_NO_NAMESPACES)
struct MapValueDeleteFunctor : public unary_function<const typename T::value_type&, void>
#else
struct MapValueDeleteFunctor : public std::unary_function<const typename T::value_type&, void>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<const typename T::value_type&, void>		BaseClassType;
#else
	typedef std::unary_function<const typename T::value_type&, void>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	/**
	 * Delete the value object in a map value pair.  The value of the pair must
	 * be of pointer type.
	 *
	 * @param thePair key-value pair
	 */
	result_type
	operator()(argument_type	thePair) const
	{
#if defined(XALAN_CANNOT_DELETE_CONST)
		delete (T*)thePair.second;
#else
		delete thePair.second;
#endif
	}
};

template<class T>
MapValueDeleteFunctor<T>
makeMapValueDeleteFunctor(const T&	/* theMap */)
{
	return MapValueDeleteFunctor<T>();
}

template <class T>
#if defined(XALAN_NO_NAMESPACES)
struct MapKeyDeleteFunctor : public unary_function<const typename T::value_type&, void>
#else
struct MapKeyDeleteFunctor : public std::unary_function<const typename T::value_type&, void>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<const typename T::value_type&, void>		BaseClassType;
#else
	typedef std::unary_function<const typename T::value_type&, void>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	/**
	 * Delete the value object in a map value pair.  The value of the pair must
	 * be of pointer type.
	 *
	 * @param thePair key-value pair
	 */
	result_type
	operator()(argument_type	thePair)
	{
		delete thePair.first;
	}
};

template<class T>
MapKeyDeleteFunctor<T>
makeMapKeyDeleteFunctor(const T&	/* theMap */)
{
	return MapKeyDeleteFunctor<T>();
}

/**
 * This functor is designed to compare 0-terminated arrays.  It substitutes
 * for the default less<type*> so that pointers to arrays can be compared,
 * rather than copies of arrays.  For example, you might want to use C-style
 * strings as keys in a map, rather than string objects.  The default
 * algorithm less<const char*> would just compare the pointers, and not the
 * vector of characters to which it points.  Using this algorithm instead of
 * the default will allow the map to work as expected.
 */
template<class T>
#if defined(XALAN_NO_NAMESPACES)
struct less_null_terminated_arrays : public binary_function<const T*, const T*, bool>
#else
struct less_null_terminated_arrays : public std::binary_function<const T*, const T*, bool>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef binary_function<const T*, const T*, bool>			BaseClassType;
#else
	typedef std::binary_function<const T*, const T*, bool>		BaseClassType;
#endif

	typedef typename BaseClassType::result_type				result_type;
	typedef typename BaseClassType::first_argument_type		first_argument_type;
	typedef typename BaseClassType::second_argument_type	second_argument_type;

	/**
	 * Compare the values of two objects.
	 *
	 *
	 * @param theLHS first object to compare
	 * @param theRHS second object to compare
	 * @return true if objects are the same
	 */
	result_type
	operator()(
			first_argument_type		theLHS,
			second_argument_type	theRHS) const
	{
		while(*theLHS && *theRHS)
		{
			if (*theLHS != *theRHS)
			{
				break;
			}
			else
			{
				theLHS++;
				theRHS++;
			}
		}

		return *theLHS < *theRHS ? true : false;
	}
};

template<class CollectionType>
class CollectionClearGuard
{
public:

	CollectionClearGuard(CollectionType&	theCollection) :
		m_collection(&theCollection)
	{
	}

	~CollectionClearGuard()
	{
		if (m_collection != 0)
		{
			m_collection->clear();
		}
	}

	void
	release()
	{
		m_collection = 0;
	}

private:

	// Not implemented...
	CollectionClearGuard(const CollectionClearGuard<CollectionType>&);

	CollectionClearGuard<CollectionType>&
	operator=(const CollectionClearGuard<CollectionType>&);

	// Data members...
	CollectionType*		m_collection;
};

template<class CollectionType, class DeleteFunctorType>
class CollectionDeleteGuard
{
public:

	CollectionDeleteGuard(CollectionType&	theCollection) :
		m_collection(&theCollection)
	{
	}

	~CollectionDeleteGuard()
	{
		if (m_collection != 0)
		{
#if !defined(XALAN_NO_NAMESPACES)
			using std::for_each;
#endif

			// Delete all of the objects in the temp vector.
			for_each(m_collection->begin(),
					 m_collection->end(),
					 DeleteFunctorType());
		}
	}

	void
	release()
	{
		m_collection = 0;
	}

private:

	// Not implemented...
	CollectionDeleteGuard(const CollectionDeleteGuard<CollectionType, DeleteFunctorType>&);

	CollectionDeleteGuard<CollectionType, DeleteFunctorType>&
	operator=(const CollectionDeleteGuard<CollectionType, DeleteFunctorType>&);

	// Data members...
	CollectionType*		m_collection;
};

#endif	// STLHELPERS_HEADER_GUARD_1357924680
<commit_msg>Added typename where it was missing.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(STLHELPERS_HEADER_GUARD_1357924680)
#define STLHELPERS_HEADER_GUARD_1357924680

// Base include file.  Must be first.
#include <Include/PlatformDefinitions.hpp>

#include <algorithm>
#include <functional>

/**
 * Functor to delete objects, used in STL iteration algorithms.
 */
template <class T>
#if defined(XALAN_NO_NAMESPACES)
struct DeleteFunctor : public unary_function<const T*, void>
#else
struct DeleteFunctor : public std::unary_function<const T*, void>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<const T*, void>	BaseClassType;
#else
	typedef std::unary_function<const T*, void>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	/**
	 * Delete the object pointed to by argument.
	 *
	 * @param thePointer pointer to object to be deleted
	 */
	result_type
	operator()(argument_type	thePointer) const
	{
#if defined(XALAN_CANNOT_DELETE_CONST)
		delete (T*)thePointer;
#else
		delete thePointer;
#endif
	}
};

#if !defined(XALAN_SGI_BASED_STL)

/**
 * Functor to retrieve the key of a key-value pair in a map, used in STL
 * iteration algorithms.
 */
template <class PairType>
#if defined(XALAN_NO_NAMESPACES)
struct select1st : public unary_function<PairType, PairType::first_type>
#else
struct select1st : public std::unary_function<PairType, typename PairType::first_type>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<PairType, PairType::first_type>	BaseClassType;
#else
	typedef std::unary_function<PairType, typename PairType::first_type>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	typedef PairType								value_type;

	/**
	 * Retrieve the key of a key-value pair.
	 *
	 * @param thePair key-value pair
	 * @return key
	 */
	result_type
	operator()(const argument_type&		thePair) const
	{
		return thePair.first;
	}
};

/**
 * Functor to retrieve the value of a key-value pair in a map, used in STL
 * iteration algorithms.
 */
template <class PairType>
#if defined(XALAN_NO_NAMESPACES)
struct select2nd : public unary_function<PairType, PairType::second_type>
#else
struct select2nd : public std::unary_function<PairType, typename PairType::second_type>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<PairType, PairType::second_type>	BaseClassType;
#else
	typedef std::unary_function<PairType, typename PairType::second_type>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	typedef PairType								value_type;

	/**
	 * Retrieve the value of a key-value pair.
	 *
	 * @param thePair key-value pair
	 * @return value
	 */
	result_type
	operator()(const argument_type&		thePair) const
	{
		return thePair.second;
	}
};

#endif

/**
 * Functor to delete value objects in maps, used in STL iteration algorithms.
 */
template <class T>
#if defined(XALAN_NO_NAMESPACES)
struct MapValueDeleteFunctor : public unary_function<const typename T::value_type&, void>
#else
struct MapValueDeleteFunctor : public std::unary_function<const typename T::value_type&, void>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<const typename T::value_type&, void>		BaseClassType;
#else
	typedef std::unary_function<const typename T::value_type&, void>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	/**
	 * Delete the value object in a map value pair.  The value of the pair must
	 * be of pointer type.
	 *
	 * @param thePair key-value pair
	 */
	result_type
	operator()(argument_type	thePair) const
	{
#if defined(XALAN_CANNOT_DELETE_CONST)
		delete (T*)thePair.second;
#else
		delete thePair.second;
#endif
	}
};

template<class T>
MapValueDeleteFunctor<T>
makeMapValueDeleteFunctor(const T&	/* theMap */)
{
	return MapValueDeleteFunctor<T>();
}

template <class T>
#if defined(XALAN_NO_NAMESPACES)
struct MapKeyDeleteFunctor : public unary_function<const typename T::value_type&, void>
#else
struct MapKeyDeleteFunctor : public std::unary_function<const typename T::value_type&, void>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef unary_function<const typename T::value_type&, void>		BaseClassType;
#else
	typedef std::unary_function<const typename T::value_type&, void>	BaseClassType;
#endif

	typedef typename BaseClassType::result_type		result_type;
	typedef typename BaseClassType::argument_type	argument_type;

	/**
	 * Delete the value object in a map value pair.  The value of the pair must
	 * be of pointer type.
	 *
	 * @param thePair key-value pair
	 */
	result_type
	operator()(argument_type	thePair)
	{
		delete thePair.first;
	}
};

template<class T>
MapKeyDeleteFunctor<T>
makeMapKeyDeleteFunctor(const T&	/* theMap */)
{
	return MapKeyDeleteFunctor<T>();
}

/**
 * This functor is designed to compare 0-terminated arrays.  It substitutes
 * for the default less<type*> so that pointers to arrays can be compared,
 * rather than copies of arrays.  For example, you might want to use C-style
 * strings as keys in a map, rather than string objects.  The default
 * algorithm less<const char*> would just compare the pointers, and not the
 * vector of characters to which it points.  Using this algorithm instead of
 * the default will allow the map to work as expected.
 */
template<class T>
#if defined(XALAN_NO_NAMESPACES)
struct less_null_terminated_arrays : public binary_function<const T*, const T*, bool>
#else
struct less_null_terminated_arrays : public std::binary_function<const T*, const T*, bool>
#endif
{
#if defined(XALAN_NO_NAMESPACES)
	typedef binary_function<const T*, const T*, bool>			BaseClassType;
#else
	typedef std::binary_function<const T*, const T*, bool>		BaseClassType;
#endif

	typedef typename BaseClassType::result_type				result_type;
	typedef typename BaseClassType::first_argument_type		first_argument_type;
	typedef typename BaseClassType::second_argument_type	second_argument_type;

	/**
	 * Compare the values of two objects.
	 *
	 *
	 * @param theLHS first object to compare
	 * @param theRHS second object to compare
	 * @return true if objects are the same
	 */
	result_type
	operator()(
			first_argument_type		theLHS,
			second_argument_type	theRHS) const
	{
		while(*theLHS && *theRHS)
		{
			if (*theLHS != *theRHS)
			{
				break;
			}
			else
			{
				theLHS++;
				theRHS++;
			}
		}

		return *theLHS < *theRHS ? true : false;
	}
};

template<class CollectionType>
class CollectionClearGuard
{
public:

	CollectionClearGuard(CollectionType&	theCollection) :
		m_collection(&theCollection)
	{
	}

	~CollectionClearGuard()
	{
		if (m_collection != 0)
		{
			m_collection->clear();
		}
	}

	void
	release()
	{
		m_collection = 0;
	}

private:

	// Not implemented...
	CollectionClearGuard(const CollectionClearGuard<CollectionType>&);

	CollectionClearGuard<CollectionType>&
	operator=(const CollectionClearGuard<CollectionType>&);

	// Data members...
	CollectionType*		m_collection;
};

template<class CollectionType, class DeleteFunctorType>
class CollectionDeleteGuard
{
public:

	CollectionDeleteGuard(CollectionType&	theCollection) :
		m_collection(&theCollection)
	{
	}

	~CollectionDeleteGuard()
	{
		if (m_collection != 0)
		{
#if !defined(XALAN_NO_NAMESPACES)
			using std::for_each;
#endif

			// Delete all of the objects in the temp vector.
			for_each(m_collection->begin(),
					 m_collection->end(),
					 DeleteFunctorType());
		}
	}

	void
	release()
	{
		m_collection = 0;
	}

private:

	// Not implemented...
	CollectionDeleteGuard(const CollectionDeleteGuard<CollectionType, DeleteFunctorType>&);

	CollectionDeleteGuard<CollectionType, DeleteFunctorType>&
	operator=(const CollectionDeleteGuard<CollectionType, DeleteFunctorType>&);

	// Data members...
	CollectionType*		m_collection;
};

#endif	// STLHELPERS_HEADER_GUARD_1357924680
<|endoftext|>


<commit_before>// Copyright Andrew Resch 2008. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/ip_filter.hpp>
#include <boost/python.hpp>
#include "gil.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{
    void add_rule(ip_filter& filter, std::string start, std::string end, int flags)
    {
        return filter.add_rule(address::from_string(start), address::from_string(end), flags);
    }

    int _access(ip_filter& filter, std::string addr)
    {
        return filter.access(address::from_string(addr));
    }
}

void bind_ip_filter()
{
    class_<ip_filter>("ip_filter")
        .def("add_rule", add_rule)
        .def("access", _access)
        .def("export_filter", allow_threads(&ip_filter::export_filter))
    ;
}

<commit_msg>Fix building in windows<commit_after>// Copyright Andrew Resch 2008. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/ip_filter.hpp>
#include <boost/python.hpp>
#include "gil.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{
    void add_rule(ip_filter& filter, std::string start, std::string end, int flags)
    {
        return filter.add_rule(address::from_string(start), address::from_string(end), flags);
    }

    int access0(ip_filter& filter, std::string addr)
    {
        return filter.access(address::from_string(addr));
    }
}

void bind_ip_filter()
{
    class_<ip_filter>("ip_filter")
        .def("add_rule", add_rule)
        .def("access", access0)
        .def("export_filter", allow_threads(&ip_filter::export_filter))
    ;
}
<|endoftext|>


<commit_before>//
// message.hpp
// ***********
//
// Copyright (c) 2018 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/config.hpp"
#include "aegis/snowflake.hpp"
#include "aegis/shards/shard.hpp"
#include "aegis/rest/rest_reply.hpp"
#include "aegis/gateway/objects/attachment.hpp"
#include "aegis/gateway/objects/embed.hpp"
#include "aegis/gateway/objects/reaction.hpp"
#include "aegis/gateway/objects/user.hpp"
#include <nlohmann/json.hpp>
#include "aegis/guild.hpp"
#include "aegis/futures.hpp"

namespace aegis
{

namespace gateway
{

namespace objects
{

/// Type of message
enum message_type
{
    Default = 0,
    RecipientAdd = 1,
    RecipientRemove = 2,
    Call = 3,
    ChannelNameChange = 4,
    ChannelIconChange = 5,
    ChannelPinnedMessage = 6,
    GuildMemberJoin = 7
};

/**\todo Needs documentation
 */
class message
{
public:
    /// Constructor for the message object
    /**
     * @param _shard Pointer to the shard this message is being handled by
     * @param _c Pointer of channel object
     * @param _g Pointer of guild object
     * @param content String of the message sent
     */
    explicit message(const std::string & content, aegis::channel * _c, aegis::guild * _g) noexcept
        : _content(content)
        , _channel(_c)
        , _guild(_g)
    {
    }

    /// Constructor for the message object
    /**
     * @param _shard Pointer to the shard this message is being handled by
     * @param channel_id Snowflake of channel this message belongs to
     * @param content String of the message sent
     */
    AEGIS_DECL void set_channel(aegis::channel * _c)
    {
        _channel = _c;
    }

    /// Constructor for the message object
    /**
     * @param _shard Pointer to the shard this message is being handled by
     * @param channel_id Snowflake of channel this message belongs to
     * @param content String of the message sent
     */
    AEGIS_DECL void set_guild(aegis::guild * _g)
    {
        _guild = _g;
    }

    explicit message() = default;

    std::string timestamp; /**<\todo Needs documentation */
    std::string edited_timestamp; /**<\todo Needs documentation */
    bool tts = false; /**<\todo Needs documentation */
    bool mention_everyone = false; /**<\todo Needs documentation */
    std::vector<snowflake> mentions; /**<\todo Needs documentation */
    std::vector<snowflake> mention_roles; /**<\todo Needs documentation */
    std::vector<objects::attachment> attachments; /**<\todo Needs documentation */
    std::vector<objects::embed> embeds; /**<\todo Needs documentation */
    bool pinned = false; /**<\todo Needs documentation */
    std::vector<objects::reaction> reactions; /**<\todo Needs documentation */
    snowflake nonce; /**<\todo Needs documentation */
    std::string webhook_id; /**<\todo Needs documentation */
    objects::message_type type = Default; /**<\todo Needs documentation */
    user author; /**< author object for this message */

    bool is_bot() const noexcept
    {
        return author.is_bot();
    }

    bool is_webhook() const noexcept
    {
        return author.is_webhook();
    }

    const std::string & get_content() const noexcept
    {
        return _content;
    }

    void set_content(const std::string & content) noexcept
    {
        _content = content;
    }

    snowflake get_id() const noexcept
    {
        return _message_id;
    }

    bool has_guild() const noexcept
    {
        return _guild != nullptr || _guild_id != 0;
    }

    bool has_channel() const noexcept
    {
        return _channel != nullptr || _channel_id != 0;
    }

#if !defined(AEGIS_DISABLE_ALL_CACHE)
    bool has_member() const noexcept
    {
        return _member != nullptr || _author_id != 0;
    }
#endif

    AEGIS_DECL aegis::guild & get_guild();

    AEGIS_DECL aegis::channel & get_channel();

#if !defined(AEGIS_DISABLE_ALL_CACHE)
    AEGIS_DECL aegis::member & get_member();
#endif

    AEGIS_DECL aegis::future<rest::rest_reply> delete_message();

    AEGIS_DECL aegis::future<rest::rest_reply> edit(const std::string & content);

    AEGIS_DECL aegis::future<rest::rest_reply> create_reaction(const std::string & content);

    AEGIS_DECL aegis::future<rest::rest_reply> delete_own_reaction(const std::string & content);

    AEGIS_DECL aegis::future<rest::rest_reply> delete_user_reaction(const std::string & content, const snowflake member_id);

    AEGIS_DECL aegis::future<rest::rest_reply> delete_all_reactions();

    /// Obtain the relevant snowflakes related to this message
    /**
     * Returns { _channel_id, _guild_id, _message_id, _author_id }
     * Some may be 0 such as guild for a DM or author for a webhook
     * @returns std::tuple<snowflake, snowflake, snowflake, snowflake>
     */
    std::tuple<snowflake, snowflake, snowflake, snowflake> get_related_ids() const noexcept
    {
        return std::tuple<snowflake, snowflake, snowflake, snowflake>{ _channel_id, _guild_id, _message_id, _author_id };
    };

private:
    friend AEGIS_DECL void from_json(const nlohmann::json& j, objects::message& m);
    friend AEGIS_DECL void to_json(nlohmann::json& j, const objects::message& m);
    friend class core;

    AEGIS_DECL void populate_self();

    std::string _content;/**< String of the message contents */
    aegis::channel * _channel = nullptr;/**< Pointer to the channel this message belongs to */
    aegis::guild * _guild = nullptr;/**< Pointer to the guild this message belongs to */
#if !defined(AEGIS_DISABLE_ALL_CACHE)
    aegis::member * _member = nullptr;/**< Pointer to the author of this message */
#endif
    snowflake _message_id = 0; /**< snowflake of the message */
    snowflake _channel_id = 0; /**< snowflake of the channel this message belongs to */
    snowflake _guild_id = 0; /**< snowflake of the guild this message belongs to */
    snowflake _author_id = 0; /**< snowflake of the author of this message */
};

/// \cond TEMPLATES
AEGIS_DECL void from_json(const nlohmann::json& j, objects::message& m);

AEGIS_DECL void to_json(nlohmann::json& j, const objects::message& m);
/// \endcond

}

}

}

#if defined(AEGIS_HEADER_ONLY)
#include "aegis/gateway/objects/impl/message.cpp"
#endif
<commit_msg>Added additional getters for ids in message object<commit_after>//
// message.hpp
// ***********
//
// Copyright (c) 2018 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/config.hpp"
#include "aegis/snowflake.hpp"
#include "aegis/shards/shard.hpp"
#include "aegis/rest/rest_reply.hpp"
#include "aegis/gateway/objects/attachment.hpp"
#include "aegis/gateway/objects/embed.hpp"
#include "aegis/gateway/objects/reaction.hpp"
#include "aegis/gateway/objects/user.hpp"
#include <nlohmann/json.hpp>
#include "aegis/guild.hpp"
#include "aegis/futures.hpp"

namespace aegis
{

namespace gateway
{

namespace objects
{

/// Type of message
enum message_type
{
    Default = 0,
    RecipientAdd = 1,
    RecipientRemove = 2,
    Call = 3,
    ChannelNameChange = 4,
    ChannelIconChange = 5,
    ChannelPinnedMessage = 6,
    GuildMemberJoin = 7
};

/**\todo Needs documentation
 */
class message
{
public:
    /// Constructor for the message object
    /**
     * @param _shard Pointer to the shard this message is being handled by
     * @param _c Pointer of channel object
     * @param _g Pointer of guild object
     * @param content String of the message sent
     */
    explicit message(const std::string & content, aegis::channel * _c, aegis::guild * _g) noexcept
        : _content(content)
        , _channel(_c)
        , _guild(_g)
    {
    }

    /// Constructor for the message object
    /**
     * @param _shard Pointer to the shard this message is being handled by
     * @param channel_id Snowflake of channel this message belongs to
     * @param content String of the message sent
     */
    AEGIS_DECL void set_channel(aegis::channel * _c)
    {
        _channel = _c;
    }

    /// Constructor for the message object
    /**
     * @param _shard Pointer to the shard this message is being handled by
     * @param channel_id Snowflake of channel this message belongs to
     * @param content String of the message sent
     */
    AEGIS_DECL void set_guild(aegis::guild * _g)
    {
        _guild = _g;
    }

    explicit message() = default;

    std::string timestamp; /**<\todo Needs documentation */
    std::string edited_timestamp; /**<\todo Needs documentation */
    bool tts = false; /**<\todo Needs documentation */
    bool mention_everyone = false; /**<\todo Needs documentation */
    std::vector<snowflake> mentions; /**<\todo Needs documentation */
    std::vector<snowflake> mention_roles; /**<\todo Needs documentation */
    std::vector<objects::attachment> attachments; /**<\todo Needs documentation */
    std::vector<objects::embed> embeds; /**<\todo Needs documentation */
    bool pinned = false; /**<\todo Needs documentation */
    std::vector<objects::reaction> reactions; /**<\todo Needs documentation */
    snowflake nonce; /**<\todo Needs documentation */
    std::string webhook_id; /**<\todo Needs documentation */
    objects::message_type type = Default; /**<\todo Needs documentation */
    user author; /**< author object for this message */

    bool is_bot() const noexcept
    {
        return author.is_bot();
    }

    bool is_webhook() const noexcept
    {
        return author.is_webhook();
    }

    const std::string & get_content() const noexcept
    {
        return _content;
    }

    void set_content(const std::string & content) noexcept
    {
        _content = content;
    }

    snowflake get_id() const noexcept
    {
        return _message_id;
    }

    snowflake get_channel_id() const noexcept
    {
        return _channel_id;
    }

    snowflake get_guild_id() const noexcept
    {
        return _guild_id;
    }

    snowflake get_author_id() const noexcept
    {
        return _author_id;
    }

    bool has_guild() const noexcept
    {
        return _guild != nullptr || _guild_id != 0;
    }

    bool has_channel() const noexcept
    {
        return _channel != nullptr || _channel_id != 0;
    }

#if !defined(AEGIS_DISABLE_ALL_CACHE)
    bool has_member() const noexcept
    {
        return _member != nullptr || _author_id != 0;
    }
#endif

    AEGIS_DECL aegis::guild & get_guild();

    AEGIS_DECL aegis::channel & get_channel();

#if !defined(AEGIS_DISABLE_ALL_CACHE)
    AEGIS_DECL aegis::member & get_member();
#endif

    AEGIS_DECL aegis::future<rest::rest_reply> delete_message();

    AEGIS_DECL aegis::future<rest::rest_reply> edit(const std::string & content);

    AEGIS_DECL aegis::future<rest::rest_reply> create_reaction(const std::string & content);

    AEGIS_DECL aegis::future<rest::rest_reply> delete_own_reaction(const std::string & content);

    AEGIS_DECL aegis::future<rest::rest_reply> delete_user_reaction(const std::string & content, const snowflake member_id);

    AEGIS_DECL aegis::future<rest::rest_reply> delete_all_reactions();

    /// Obtain the relevant snowflakes related to this message
    /**
     * Returns { _channel_id, _guild_id, _message_id, _author_id }
     * Some may be 0 such as guild for a DM or author for a webhook
     * @returns std::tuple<snowflake, snowflake, snowflake, snowflake>
     */
    std::tuple<snowflake, snowflake, snowflake, snowflake> get_related_ids() const noexcept
    {
        return std::tuple<snowflake, snowflake, snowflake, snowflake>{ _channel_id, _guild_id, _message_id, _author_id };
    };

private:
    friend AEGIS_DECL void from_json(const nlohmann::json& j, objects::message& m);
    friend AEGIS_DECL void to_json(nlohmann::json& j, const objects::message& m);
    friend class core;

    AEGIS_DECL void populate_self();

    std::string _content;/**< String of the message contents */
    aegis::channel * _channel = nullptr;/**< Pointer to the channel this message belongs to */
    aegis::guild * _guild = nullptr;/**< Pointer to the guild this message belongs to */
#if !defined(AEGIS_DISABLE_ALL_CACHE)
    aegis::member * _member = nullptr;/**< Pointer to the author of this message */
#endif
    snowflake _message_id = 0; /**< snowflake of the message */
    snowflake _channel_id = 0; /**< snowflake of the channel this message belongs to */
    snowflake _guild_id = 0; /**< snowflake of the guild this message belongs to */
    snowflake _author_id = 0; /**< snowflake of the author of this message */
};

/// \cond TEMPLATES
AEGIS_DECL void from_json(const nlohmann::json& j, objects::message& m);

AEGIS_DECL void to_json(nlohmann::json& j, const objects::message& m);
/// \endcond

}

}

}

#if defined(AEGIS_HEADER_ONLY)
#include "aegis/gateway/objects/impl/message.cpp"
#endif
<|endoftext|>


<commit_before>#ifndef _FM_INDEX_FM_INDEX_HPP
#define _FM_INDEX_FM_INDEX_HPP

#include "wavelet_tree_huffman.hpp"
#include "wavelet_tree_binary.hpp"
#include "wavelet_matrix.hpp"
#include <am/succinct/rsdic/RSDic.hpp>
#include <am/succinct/sdarray/SDArray.hpp>
#include <am/succinct/sais/sais.hxx>

#include <algorithm>

NS_IZENELIB_AM_BEGIN

namespace succinct
{
namespace fm_index
{

template <class CharT>
class FMIndex
{
public:
    enum
    {
        HUFFMAN = 0,
        BINARY,
        NA
    };

    typedef CharT char_type;

    FMIndex(uint32_t samplerate = 64);
    ~FMIndex();

    void clear();

    void addDoc(const char_type *text, size_t len);
    void setOrigText(std::vector<char_type> &orig_text);

    void build();
    void reconstructText(const std::vector<uint32_t> &del_docid_list, std::vector<char_type> &orig_text);

    size_t backwardSearch(const char_type *pattern, size_t len, std::pair<size_t, size_t> &match_range) const;
    size_t longestSuffixMatch(const char_type *patter, size_t len, std::vector<std::pair<size_t, size_t> > &match_ranges) const;

    void getMatchedDocIdList(const std::pair<size_t, size_t> &match_range, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const;
    void getMatchedDocIdList(const std::vector<std::pair<size_t, size_t> > &match_ranges, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const;

    size_t length() const;
    size_t allocSize() const;

    size_t bufferLength() const;
    size_t docCount() const;

    void save(std::ostream &ostr) const;
    void load(std::istream &istr);

private:
    template <class T>
    WaveletTree<T> *getWaveletTree_(size_t charset_size) const
    {
        if (charset_size <= 65536)
        {
            return new WaveletTreeHuffman<T>(charset_size);
        }
        else
        {
            return new WaveletMatrix<T>(charset_size);
        }
    }

private:
    size_t samplerate_;
    size_t length_;
    size_t alphabet_num_;

    sdarray::SDArray doc_delim_;

    WaveletTree<char_type> *bwt_tree_;
    WaveletTree<uint32_t> *doc_array_;

    std::vector<char_type> temp_text_;
};

template <class CharT>
FMIndex<CharT>::FMIndex(uint32_t samplerate)
    : samplerate_(samplerate)
    , length_(), alphabet_num_()
    , bwt_tree_()
    , doc_array_()
{
}

template <class CharT>
FMIndex<CharT>::~FMIndex()
{
    if (bwt_tree_) delete bwt_tree_;
    if (doc_array_) delete doc_array_;
}

template <class CharT>
void FMIndex<CharT>::clear()
{
    samplerate_ = 0;
    length_ = 0;
    alphabet_num_ = 0;

    doc_delim_.clear();

    if (bwt_tree_)
    {
        delete bwt_tree_;
        bwt_tree_ = NULL;
    }
    if (doc_array_)
    {
        delete doc_array_;
        doc_array_ = NULL;
    }

    std::vector<char_type>().swap(temp_text_);
}

template <class CharT>
void FMIndex<CharT>::addDoc(const char_type *text, size_t len)
{
    temp_text_.insert(temp_text_.end(), text, text + len);
    temp_text_.push_back(003);
}

template <class CharT>
void FMIndex<CharT>::setOrigText(std::vector<char_type> &orig_text)
{
    temp_text_.swap(orig_text);
}

template <class CharT>
void FMIndex<CharT>::build()
{
    temp_text_.push_back('\0');
    length_ = temp_text_.size();
    alphabet_num_ = WaveletTree<char_type>::getAlphabetNum(&temp_text_[0], length_);

    std::vector<int32_t> sa(length_);
    if (saisxx(temp_text_.begin(), sa.begin(), (int32_t)length_, (int32_t)alphabet_num_) < 0)
    {
        std::vector<char_type>().swap(temp_text_);
        return;
    }

    size_t pos = 0;
    while (temp_text_[pos] != 003) ++pos;
    doc_delim_.add(pos + 1);
    for (size_t i = pos + 1; i < length_; ++i)
    {
        if (temp_text_[i] == 003)
        {
            doc_delim_.add(i - pos);
            pos = i;
        }
    }
    doc_delim_.build();

    std::vector<char_type> bwt(length_);
    for (size_t i = 0; i < length_; ++i)
    {
        if (sa[i] == 0)
        {
            bwt[i] = temp_text_[length_ - 1];
            sa[i] = docCount();
        }
        else
        {
            bwt[i] = temp_text_[sa[i] - 1];
            sa[i] = doc_delim_.find(sa[i] - 1);
        }
    }

    std::vector<char_type>().swap(temp_text_);

    bwt_tree_ = getWaveletTree_<char_type>(alphabet_num_);
    bwt_tree_->build(&bwt[0], length_);

    std::vector<char_type>().swap(bwt);

    doc_array_ = getWaveletTree_<uint32_t>(docCount());
    doc_array_->build((uint32_t *)&sa[0], length_);

    std::vector<int32_t>().swap(sa);

    --length_;
}

template <class CharT>
void FMIndex<CharT>::reconstructText(const std::vector<uint32_t> &del_docid_list, std::vector<char_type> &orig_text)
{
    orig_text.resize(length_);

    size_t pos = 0;
    char_type c;

    for (size_t i = 0; i < length_; ++i)
    {
        c = bwt_tree_->access(pos, pos);
        orig_text[length_ - i - 1] = c;
        pos += bwt_tree_->getOcc(c);
    }

    if (del_docid_list.empty() || del_docid_list[0] > doc_delim_.size()) return;

    size_t old_pos = doc_delim_.prefixSum(del_docid_list[0] - 1);
    size_t new_pos = doc_delim_.prefixSum(del_docid_list[0]) - 1;

    for (size_t i = 1; i < del_docid_list.size() && del_docid_list[i] <= doc_delim_.size(); ++i)
    {
        pos = doc_delim_.prefixSum(del_docid_list[i] - 1);
        if (old_pos == new_pos)
        {
            old_pos = pos;
        }
        else
        {
            for (; new_pos < pos; ++old_pos, ++new_pos)
            {
                orig_text[old_pos] = orig_text[new_pos];
            }
        }
        new_pos = doc_delim_.prefixSum(del_docid_list[i]) - 1;
    }

    if (old_pos != new_pos)
    {
        for (; new_pos < length_; ++old_pos, ++new_pos)
        {
            orig_text[old_pos] = orig_text[new_pos];
        }
        orig_text.resize(old_pos);
    }
}

template <class CharT>
size_t FMIndex<CharT>::backwardSearch(const char_type *pattern, size_t len, std::pair<size_t, size_t> &match_range) const
{
    size_t orig_len = len;

    char_type c = pattern[--len];
    size_t occ;

    size_t sp = bwt_tree_->getOcc(c);
    size_t ep = bwt_tree_->getOcc(c + 1);
    if (sp == ep) return 0;

    match_range.first = sp;
    match_range.second = ep;

    for (; len > 0; --len)
    {
        c = pattern[len - 1];
        occ = bwt_tree_->getOcc(c);

        sp = occ + bwt_tree_->rank(c, sp);
        ep = occ + bwt_tree_->rank(c, ep);
        if (sp == ep) break;

        match_range.first = sp;
        match_range.second = ep;
    }

    return orig_len - len;
}

template <class CharT>
size_t FMIndex<CharT>::longestSuffixMatch(const char_type *pattern, size_t len, std::vector<std::pair<size_t, size_t> > &match_ranges) const
{
    std::pair<size_t, size_t> match_range;
    std::vector<std::pair<size_t, size_t> > prune_bounds(len);

    size_t max_match = 0;
    char_type c;
    size_t occ, sp, ep;
    size_t i, j;

    for (i = len; i > max_match; --i)
    {
        c = pattern[i - 1];

        sp = bwt_tree_->getOcc(c);
        ep = bwt_tree_->getOcc(c + 1);

        if (ep - sp <= prune_bounds[i - 1].second - prune_bounds[i - 1].first)
            goto PRUNED;

        match_range.first = sp;
        match_range.second = ep;
        prune_bounds[i - 1] = match_range;

        for (j = i - 1; j > 0; --j)
        {
            c = pattern[j - 1];
            occ = bwt_tree_->getOcc(c);

            sp = occ + bwt_tree_->rank(c, sp);
            ep = occ + bwt_tree_->rank(c, ep);

            if (sp == ep) break;

            if (ep - sp <= prune_bounds[j - 1].second - prune_bounds[j - 1].first)
                goto PRUNED;

            match_range.first = sp;
            match_range.second = ep;
            prune_bounds[j - 1] = match_range;
        }

        if (max_match < i - j)
        {
            max_match = i - j;
            match_ranges.clear();
            match_ranges.push_back(match_range);
        }
        else if (max_match == i - j)
        {
            match_ranges.push_back(match_range);
        }

PRUNED:
        assert(true);
    }

    return max_match;
}

template <class CharT>
void FMIndex<CharT>::getMatchedDocIdList(const std::pair<size_t, size_t> &match_range, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const
{
    char_type c;
    size_t pos, dist;

    for (size_t i = match_range.first; i < match_range.second; ++i)
    {
        docid_list.push_back(doc_array_->access(i) + 1);
        if (docid_list.size() == max_docs) break;
    }

    std::sort(docid_list.begin(), docid_list.end());
    docid_list.erase(std::unique(docid_list.begin(), docid_list.end()), docid_list.end());

    doclen_list.resize(docid_list.size());
    for (size_t i = 0; i < docid_list.size(); ++i)
    {
        doclen_list[i] = doc_delim_.getVal(docid_list[i] - 1) - 1;
    }
}

template <class CharT>
void FMIndex<CharT>::getMatchedDocIdList(const std::vector<std::pair<size_t, size_t> > &match_ranges, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const
{
    char_type c;
    size_t pos, dist;

    for (std::vector<std::pair<size_t, size_t> >::const_iterator it = match_ranges.begin();
            it != match_ranges.end(); ++it)
    {
        for (size_t i = it->first; i < it->second; ++i)
        {
            docid_list.push_back(doc_array_->access(i) + 1);
            if (docid_list.size() == max_docs) goto EXIT;
        }
    }

EXIT:
    std::sort(docid_list.begin(), docid_list.end());
    docid_list.erase(std::unique(docid_list.begin(), docid_list.end()), docid_list.end());

    doclen_list.resize(docid_list.size());
    for (size_t i = 0; i < docid_list.size(); ++i)
    {
        doclen_list[i] = doc_delim_.getVal(docid_list[i] - 1) - 1;
    }
}

template <class CharT>
size_t FMIndex<CharT>::length() const
{
    return length_;
}

template <class CharT>
size_t FMIndex<CharT>::allocSize() const
{
    return sizeof(FMIndex)
        + doc_delim_.allocSize() - sizeof(sdarray::SDArray)
        + bwt_tree_->allocSize();
}

template <class CharT>
size_t FMIndex<CharT>::bufferLength() const
{
    return temp_text_.size();
}

template <class CharT>
size_t FMIndex<CharT>::docCount() const
{
    return doc_delim_.size();
}

template <class CharT>
void FMIndex<CharT>::save(std::ostream &ostr) const
{
    ostr.write((const char *)&samplerate_,   sizeof(samplerate_));
    ostr.write((const char *)&length_,       sizeof(length_));
    ostr.write((const char *)&alphabet_num_, sizeof(alphabet_num_));

    doc_delim_.save(ostr);
    bwt_tree_->save(ostr);
    doc_array_->save(ostr);
}

template <class CharT>
void FMIndex<CharT>::load(std::istream &istr)
{
    istr.read((char *)&samplerate_,   sizeof(samplerate_));
    istr.read((char *)&length_,       sizeof(length_));
    istr.read((char *)&alphabet_num_, sizeof(alphabet_num_));

    doc_delim_.load(istr);
    bwt_tree_ = getWaveletTree_<char_type>(alphabet_num_);
    bwt_tree_->load(istr);
    doc_array_ = getWaveletTree_<uint32_t>(alphabet_num_);
    doc_array_->load(istr);
}

}
}

NS_IZENELIB_AM_END

#endif
<commit_msg>fix a bug in FMIndex::load()<commit_after>#ifndef _FM_INDEX_FM_INDEX_HPP
#define _FM_INDEX_FM_INDEX_HPP

#include "wavelet_tree_huffman.hpp"
#include "wavelet_tree_binary.hpp"
#include "wavelet_matrix.hpp"
#include <am/succinct/rsdic/RSDic.hpp>
#include <am/succinct/sdarray/SDArray.hpp>
#include <am/succinct/sais/sais.hxx>

#include <algorithm>

NS_IZENELIB_AM_BEGIN

namespace succinct
{
namespace fm_index
{

template <class CharT>
class FMIndex
{
public:
    typedef CharT char_type;

    FMIndex();
    ~FMIndex();

    void clear();

    void addDoc(const char_type *text, size_t len);
    void setOrigText(std::vector<char_type> &orig_text);

    void build();
    void reconstructText(const std::vector<uint32_t> &del_docid_list, std::vector<char_type> &orig_text);

    size_t backwardSearch(const char_type *pattern, size_t len, std::pair<size_t, size_t> &match_range) const;
    size_t longestSuffixMatch(const char_type *patter, size_t len, std::vector<std::pair<size_t, size_t> > &match_ranges) const;

    void getMatchedDocIdList(const std::pair<size_t, size_t> &match_range, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const;
    void getMatchedDocIdList(const std::vector<std::pair<size_t, size_t> > &match_ranges, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const;

    size_t length() const;
    size_t allocSize() const;

    size_t bufferLength() const;
    size_t docCount() const;

    void save(std::ostream &ostr) const;
    void load(std::istream &istr);

private:
    template <class T>
    WaveletTree<T> *getWaveletTree_(size_t charset_size) const
    {
        if (charset_size <= 65536)
        {
            return new WaveletTreeHuffman<T>(charset_size);
        }
        else
        {
            return new WaveletMatrix<T>(charset_size);
        }
    }

private:
    size_t length_;
    size_t alphabet_num_;

    sdarray::SDArray doc_delim_;

    WaveletTree<char_type> *bwt_tree_;
    WaveletTree<uint32_t> *doc_array_;

    std::vector<char_type> temp_text_;
};

template <class CharT>
FMIndex<CharT>::FMIndex()
    : length_(), alphabet_num_()
    , bwt_tree_()
    , doc_array_()
{
}

template <class CharT>
FMIndex<CharT>::~FMIndex()
{
    if (bwt_tree_) delete bwt_tree_;
    if (doc_array_) delete doc_array_;
}

template <class CharT>
void FMIndex<CharT>::clear()
{
    length_ = 0;
    alphabet_num_ = 0;

    doc_delim_.clear();

    if (bwt_tree_)
    {
        delete bwt_tree_;
        bwt_tree_ = NULL;
    }
    if (doc_array_)
    {
        delete doc_array_;
        doc_array_ = NULL;
    }

    std::vector<char_type>().swap(temp_text_);
}

template <class CharT>
void FMIndex<CharT>::addDoc(const char_type *text, size_t len)
{
    temp_text_.insert(temp_text_.end(), text, text + len);
    temp_text_.push_back(003);
}

template <class CharT>
void FMIndex<CharT>::setOrigText(std::vector<char_type> &orig_text)
{
    temp_text_.swap(orig_text);
}

template <class CharT>
void FMIndex<CharT>::build()
{
    temp_text_.push_back('\0');
    length_ = temp_text_.size();
    alphabet_num_ = WaveletTree<char_type>::getAlphabetNum(&temp_text_[0], length_);

    std::vector<int32_t> sa(length_);
    if (saisxx(temp_text_.begin(), sa.begin(), (int32_t)length_, (int32_t)alphabet_num_) < 0)
    {
        std::vector<char_type>().swap(temp_text_);
        return;
    }

    size_t pos = 0;
    while (temp_text_[pos] != 003) ++pos;
    doc_delim_.add(pos + 1);
    for (size_t i = pos + 1; i < length_; ++i)
    {
        if (temp_text_[i] == 003)
        {
            doc_delim_.add(i - pos);
            pos = i;
        }
    }
    doc_delim_.build();

    std::vector<char_type> bwt(length_);
    for (size_t i = 0; i < length_; ++i)
    {
        if (sa[i] == 0)
        {
            bwt[i] = temp_text_[length_ - 1];
            sa[i] = docCount();
        }
        else
        {
            bwt[i] = temp_text_[sa[i] - 1];
            sa[i] = doc_delim_.find(sa[i] - 1);
        }
    }

    std::vector<char_type>().swap(temp_text_);

    bwt_tree_ = getWaveletTree_<char_type>(alphabet_num_);
    bwt_tree_->build(&bwt[0], length_);

    std::vector<char_type>().swap(bwt);

    doc_array_ = getWaveletTree_<uint32_t>(docCount());
    doc_array_->build((uint32_t *)&sa[0], length_);

    std::vector<int32_t>().swap(sa);

    --length_;
}

template <class CharT>
void FMIndex<CharT>::reconstructText(const std::vector<uint32_t> &del_docid_list, std::vector<char_type> &orig_text)
{
    orig_text.resize(length_);

    size_t pos = 0;
    char_type c;

    for (size_t i = 0; i < length_; ++i)
    {
        c = bwt_tree_->access(pos, pos);
        orig_text[length_ - i - 1] = c;
        pos += bwt_tree_->getOcc(c);
    }

    if (del_docid_list.empty() || del_docid_list[0] > doc_delim_.size()) return;

    size_t old_pos = doc_delim_.prefixSum(del_docid_list[0] - 1);
    size_t new_pos = doc_delim_.prefixSum(del_docid_list[0]) - 1;

    for (size_t i = 1; i < del_docid_list.size() && del_docid_list[i] <= doc_delim_.size(); ++i)
    {
        pos = doc_delim_.prefixSum(del_docid_list[i] - 1);
        if (old_pos == new_pos)
        {
            old_pos = pos;
        }
        else
        {
            for (; new_pos < pos; ++old_pos, ++new_pos)
            {
                orig_text[old_pos] = orig_text[new_pos];
            }
        }
        new_pos = doc_delim_.prefixSum(del_docid_list[i]) - 1;
    }

    if (old_pos != new_pos)
    {
        for (; new_pos < length_; ++old_pos, ++new_pos)
        {
            orig_text[old_pos] = orig_text[new_pos];
        }
        orig_text.resize(old_pos);
    }
}

template <class CharT>
size_t FMIndex<CharT>::backwardSearch(const char_type *pattern, size_t len, std::pair<size_t, size_t> &match_range) const
{
    size_t orig_len = len;

    char_type c = pattern[--len];
    size_t occ;

    size_t sp = bwt_tree_->getOcc(c);
    size_t ep = bwt_tree_->getOcc(c + 1);
    if (sp == ep) return 0;

    match_range.first = sp;
    match_range.second = ep;

    for (; len > 0; --len)
    {
        c = pattern[len - 1];
        occ = bwt_tree_->getOcc(c);

        sp = occ + bwt_tree_->rank(c, sp);
        ep = occ + bwt_tree_->rank(c, ep);
        if (sp == ep) break;

        match_range.first = sp;
        match_range.second = ep;
    }

    return orig_len - len;
}

template <class CharT>
size_t FMIndex<CharT>::longestSuffixMatch(const char_type *pattern, size_t len, std::vector<std::pair<size_t, size_t> > &match_ranges) const
{
    std::pair<size_t, size_t> match_range;
    std::vector<std::pair<size_t, size_t> > prune_bounds(len);

    size_t max_match = 0;
    char_type c;
    size_t occ, sp, ep;
    size_t i, j;

    for (i = len; i > max_match; --i)
    {
        c = pattern[i - 1];

        sp = bwt_tree_->getOcc(c);
        ep = bwt_tree_->getOcc(c + 1);

        if (ep - sp <= prune_bounds[i - 1].second - prune_bounds[i - 1].first)
            goto PRUNED;

        match_range.first = sp;
        match_range.second = ep;
        prune_bounds[i - 1] = match_range;

        for (j = i - 1; j > 0; --j)
        {
            c = pattern[j - 1];
            occ = bwt_tree_->getOcc(c);

            sp = occ + bwt_tree_->rank(c, sp);
            ep = occ + bwt_tree_->rank(c, ep);

            if (sp == ep) break;

            if (ep - sp <= prune_bounds[j - 1].second - prune_bounds[j - 1].first)
                goto PRUNED;

            match_range.first = sp;
            match_range.second = ep;
            prune_bounds[j - 1] = match_range;
        }

        if (max_match < i - j)
        {
            max_match = i - j;
            match_ranges.clear();
            match_ranges.push_back(match_range);
        }
        else if (max_match == i - j)
        {
            match_ranges.push_back(match_range);
        }

PRUNED:
        assert(true);
    }

    return max_match;
}

template <class CharT>
void FMIndex<CharT>::getMatchedDocIdList(const std::pair<size_t, size_t> &match_range, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const
{
    char_type c;
    size_t pos, dist;

    for (size_t i = match_range.first; i < match_range.second; ++i)
    {
        docid_list.push_back(doc_array_->access(i) + 1);
        if (docid_list.size() == max_docs) break;
    }

    std::sort(docid_list.begin(), docid_list.end());
    docid_list.erase(std::unique(docid_list.begin(), docid_list.end()), docid_list.end());

    doclen_list.resize(docid_list.size());
    for (size_t i = 0; i < docid_list.size(); ++i)
    {
        doclen_list[i] = doc_delim_.getVal(docid_list[i] - 1) - 1;
    }
}

template <class CharT>
void FMIndex<CharT>::getMatchedDocIdList(const std::vector<std::pair<size_t, size_t> > &match_ranges, size_t max_docs, std::vector<uint32_t> &docid_list, std::vector<size_t> &doclen_list) const
{
    char_type c;
    size_t pos, dist;

    for (std::vector<std::pair<size_t, size_t> >::const_iterator it = match_ranges.begin();
            it != match_ranges.end(); ++it)
    {
        for (size_t i = it->first; i < it->second; ++i)
        {
            docid_list.push_back(doc_array_->access(i) + 1);
            if (docid_list.size() == max_docs) goto EXIT;
        }
    }

EXIT:
    std::sort(docid_list.begin(), docid_list.end());
    docid_list.erase(std::unique(docid_list.begin(), docid_list.end()), docid_list.end());

    doclen_list.resize(docid_list.size());
    for (size_t i = 0; i < docid_list.size(); ++i)
    {
        doclen_list[i] = doc_delim_.getVal(docid_list[i] - 1) - 1;
    }
}

template <class CharT>
size_t FMIndex<CharT>::length() const
{
    return length_;
}

template <class CharT>
size_t FMIndex<CharT>::allocSize() const
{
    return sizeof(FMIndex)
        + doc_delim_.allocSize() - sizeof(sdarray::SDArray)
        + bwt_tree_->allocSize() + doc_array_->allocSize();
}

template <class CharT>
size_t FMIndex<CharT>::bufferLength() const
{
    return temp_text_.size();
}

template <class CharT>
size_t FMIndex<CharT>::docCount() const
{
    return doc_delim_.size();
}

template <class CharT>
void FMIndex<CharT>::save(std::ostream &ostr) const
{
    ostr.write((const char *)&length_,       sizeof(length_));
    ostr.write((const char *)&alphabet_num_, sizeof(alphabet_num_));

    doc_delim_.save(ostr);
    bwt_tree_->save(ostr);
    doc_array_->save(ostr);
}

template <class CharT>
void FMIndex<CharT>::load(std::istream &istr)
{
    istr.read((char *)&length_,       sizeof(length_));
    istr.read((char *)&alphabet_num_, sizeof(alphabet_num_));

    doc_delim_.load(istr);
    bwt_tree_ = getWaveletTree_<char_type>(alphabet_num_);
    bwt_tree_->load(istr);
    doc_array_ = getWaveletTree_<uint32_t>(docCount());
    doc_array_->load(istr);
}

}
}

NS_IZENELIB_AM_END

#endif
<|endoftext|>


<commit_before>#include "matchwidget.h"
#include <iostream>
#include <cmath>

using namespace std;

MatchWidget::MatchWidget(Match * startingMatch, bool isGuest, int matchID, MainWindow * parent):
    QWidget(parent), parent_(parent), isGuest_(isGuest), matchID_(matchID) {
    //-----------------------MATCH INITIALISATION-----------------------
    currentMatch_ = startingMatch;

    //-------------------------SIZE SETTINGS---------------------------
    this->setFixedHeight(720);
    this->setFixedWidth(1280);

    //----------------------BACKGROUND SETTINGS---------------------------
    QVBoxLayout * layout = new QVBoxLayout;
    QLabel * image = new QLabel(this);
    image->setPixmap(QPixmap(ROOT_DIR + "/images/Quidditch_pitch_hogwarts.jpg"));
    layout->addWidget(image);

    //---------------------MAIN CONTAINER WIDGET---------------------------
    mainWidget = new QWidget(this);
    mainWidget->setFixedHeight(720);
    mainWidget->setFixedWidth(1280);
    QGridLayout * mainLayout = new QGridLayout(mainWidget);

    //------------------------SCORE SETTINGS--------------------------------
    int playerScore = currentMatch_->getScore()[0];
    ownScore = new QLabel("YOU : " + QString::fromStdString(std::to_string(playerScore)), mainWidget);
    ownScore->setFixedSize(250, 75);
    QFont font;
    font.setPointSize(17);
    ownScore->setStyleSheet(" font-weight: bold; font-size: 18pt; color : red;");
    ownScore->setAlignment(Qt::AlignBottom | Qt::AlignJustify);
    ownScore->setWordWrap(true);
    ownScore->setFont(font);
    ownScore->move(100, 50);
    ownScore->show();

    int otherScore = currentMatch_->getScore()[1];
    opponentScore = new QLabel("OPPONENT : " + QString::fromStdString(std::to_string(otherScore)), mainWidget);
    opponentScore->setFixedSize(250, 75);
    opponentScore->setAlignment(Qt::AlignBottom | Qt::AlignJustify);
    opponentScore->setStyleSheet(" font-weight: bold; font-size: 18pt; color : red;");
    opponentScore->setWordWrap(true);
    opponentScore->setFont(font);
    opponentScore->move(1000, 50);
    opponentScore->show();

    //---------------------FIELD CONTAINER WIDGET--------------------------
    fieldWidget  = new QFrame(mainWidget);

    //---------------------FIELD REPRESENTATION----------------------------

    fieldWidget->setFixedSize(QSize(LENGTH * 20, WIDTH * 17));
    QWidget * temp = new QWidget(fieldWidget);

    temp->setFixedSize((mainWidget->height() - WIDTH * 20) / 2, (mainWidget->width() - LENGTH * 20) / 2);
    mainLayout->setRowMinimumHeight(0, 100);
    mainLayout->addWidget(temp, 0, 0);
    mainLayout->addWidget(fieldWidget, 1, 1);

    turnEndButton = new QPushButton("End of turn", mainWidget);
    turnEndButton->setMinimumHeight(30);
    mainLayout->addWidget(turnEndButton, 2, 2);

    QPushButton * surrenderButton = new QPushButton("Surrender", mainWidget);
    surrenderButton->setMinimumHeight(30);
    mainLayout->addWidget(surrenderButton, 2, 3);

    //----------------------BUTTONS SIGNALS CONNECT-------------------------
    QObject::connect(turnEndButton, SIGNAL(clicked()), this, SLOT(endTurn()));
    QObject::connect(surrenderButton, SIGNAL(clicked()), this, SLOT(surrender()));

    //----------------------CUSTOM SIGNALS CONNECT-------------------------

    QObject::connect(parent_, SIGNAL(updateMatch(Match *)), this, SLOT(setCurrentMatch(Match *)));
    QObject::connect(parent_, SIGNAL(endMatch(int)), this, SLOT(endMatch(int)));

    //--------------------------START------------------------------
    currentMatch_->getGrid(grid_);
    label = 0;
    refreshField();

    mainWidget->show();

}

void MatchWidget::refreshField() {
    this->hide();
    ownScore->setText("YOU : " + QString::fromStdString(std::to_string(currentMatch_->getScore()[isGuest_])));
    opponentScore->setText("OPPONENT : " + QString::fromStdString(std::to_string(currentMatch_->getScore()[!isGuest_])));

    label = new QLabel(fieldWidget);
    QPixmap * pixmap = new QPixmap(LENGTH * 20, WIDTH * 17);
    pixmap->fill(Qt::transparent);

    QPainter painter(pixmap);
    Hexagon hexagon[WIDTH][LENGTH];
    QBrush * grass = new QBrush(QImage(ROOT_DIR + "/images/grass.jpg"));

    int xlabelDifference = 22;
    int ylabelDifference = 7;
    double x = 0;
    double y = 0;
    bool pair = true;
    bool highlighted;
    bool chosen;
    for (int i = 0; i < WIDTH; ++i) {
        for (int j = 0; j < LENGTH; ++j) {
            highlighted = false;
            chosen = false;
            hexagon[i][j].setX(x);
            hexagon[i][j].setY(y);
            hexagon[i][j].setCorners();

            x += 18;
            if (grid_[i][j].type == USABLE) {
                if (isCaseHighlighted(i, j)) {
                    painter.setBrush(QBrush(QColor(71, 158, 158)));
                    highlighted = true;
                }
                else if (isInChosenWays(i, j)) {
                    painter.setBrush(QBrush(QColor(85, 18, 201)));
                    chosen = true;
                }
                if (grid_[i][j].player != 0) {
                    if (!highlighted && !chosen) {
                        if (grid_[i][j].player->isInGuestTeam() == isGuest_) {
                            painter.setBrush(QBrush(Qt::blue));
                        }
                        else {
                            painter.setBrush(QBrush(Qt::red));
                        }
                    }
                    if (grid_[i][j].player->getRole() == KEEPER) {
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][KEEPER] = new QLabel("K", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][KEEPER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                    else if (grid_[i][j].player->getRole() == CHASER) {
                        if(grid_[i][j].player->hasQuaffle()){
                            if(grid_[i][j].player->isInGuestTeam() == isGuest_){
                                painter.setBrush(QBrush(QColor(0, 100, 0)));
                            }
                            else{
                                painter.setBrush(QBrush(QColor(255, 120, 31)));
                            }
                        }
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][CHASER] = new QLabel("C", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][CHASER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                    else if (grid_[i][j].player->getRole() == SEEKER) {
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][SEEKER] = new QLabel("S", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][SEEKER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                    else if (grid_[i][j].player->getRole() == BEATER) {
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][BEATER] = new QLabel("B", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][BEATER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                }
                else if (grid_[i][j].ball != 0) {
                    string ballName = grid_[i][j].ball->getName();
                    if (ballName == "B") {
                        painter.setBrush(QBrush(Qt::black));
                    }
                    else if (ballName == "Q") {
                        painter.setBrush(QBrush(QColor(140, 52, 52)));
                    }
                    else { //ballName == "G"
                        painter.setBrush(QBrush(Qt::yellow));
                    }
                }
                else {
                    if (!highlighted && !chosen) {
                        painter.setBrush(*grass);
                    }
                }
                if (highlighted) {
                    painter.drawPolygon(hexagon[i][j].hexagon_);
                }
                else {
                    painter.drawPolygon(hexagon[i][j].hexagon_);
                }
            }
            else if (grid_[i][j].type == GOAL) {
                painter.setBrush(QBrush(QColor(64, 64, 72)));
                painter.drawPolygon(hexagon[i][j].hexagon_);
            }
        }
        y += 15;
        if (pair) {
            x = 35;
        }
        else {
            x = 26;
        }
        pair = !pair;
    }
    label->setPixmap(*pixmap);

    this->show();
}

bool MatchWidget::isInChosenWays(unsigned x, unsigned y) {
    for (int i = 0; i < chosenWays.size(); ++i) {
        for (int j = 0; j < chosenWays[i].size(); ++j) {
            if ((chosenWays[i][j].x == x) && (chosenWays[i][j].y == y)) {
                return true;
            }
        }
    }
    return false;
}

bool MatchWidget::isCaseHighlighted(unsigned a, unsigned b) {
    for (size_t i = 0; i < highlightedCases.size(); ++i) {
        if ((highlightedCases[i].x == a) && (highlightedCases[i].y == b)) {
            return true;
        }
    }
    return false;
}

MatchWidget::~MatchWidget() {}

void MatchWidget::setCurrentMatch(Match * match) {
    turnEndButton->setEnabled(true);
    turnEndButton->setStyleSheet("color : white;");
    currentMatch_ = match;
    Case grid[WIDTH][LENGTH];
    currentMatch_->getGrid(grid);
    for (int i = 0; i < WIDTH; ++i) {
        for (int j = 0; j < LENGTH; ++j) {
            grid_[i][j] = grid[i][j];
        }
    }

    refreshField();
}

Position MatchWidget::getCase(QMouseEvent * event) {
    int row = 0;
    int column = 0;
    double hexagonHeight = 18;
    double hexagonWidth = 15;
    double halfHeight = hexagonHeight / 2;
    int startHeight = 103;
    int startWidth = 144;

    if ((event->x() > startHeight) && (event->x() < 1200)) {
        if ((event->y() > startWidth) && (event->y() < 580)) {

            // These will represent which box the mouse is in, not which hexagon!
            row = (event->y() - startWidth) / hexagonWidth;
            bool rowIsOdd = row % 2 == 0;

            // Is the row an even number?
            if (rowIsOdd) {
                column = ((event->x() - startHeight) / hexagonHeight);
            }
            else {
                column = ((event->x() - startHeight + halfHeight) / hexagonHeight);
            }
        }
    }
    Position mouseCase;
    mouseCase.x = row + 1;
    mouseCase.y = column;
    return mouseCase;
}

void MatchWidget::endTurn() {
    turnEndButton->setDisabled(true);
    turnEndButton->setStyleSheet("color : black;");
    sviews::endTurn(parent_->getSocket(), chosenWays);
    chosenWays.clear();

}

void MatchWidget::surrender() {
    sviews::surrenders(parent_->getSocket(), matchID_);

}

void MatchWidget::mousePressEvent(QMouseEvent * event) {
    if (event->button() == Qt::RightButton) {
        highlightedCases.clear();
        refreshField();
    }
    else {
        Position clickedCase = getCase(event);
        if (highlightedCases.empty()) {
            int i = clickedCase.x;
            int j = clickedCase.y;
            if ((grid_[i][j].player != 0) && (grid_[i][j].player->isInGuestTeam() == isGuest_)) {
                highlightedCases.push_back(clickedCase);
            }
        }
        else {
            if (isCloseCase(clickedCase, highlightedCases[highlightedCases.size() - 1], 0)) {
                highlightedCases.push_back(clickedCase);
            }
            else if (highlightedCases[highlightedCases.size() - 1] == clickedCase) {
                emit this->nextPlayer();
            }
        }
        refreshField();
    }
}

void MatchWidget::endMatch(int signal) {
    QString message;
    switch (signal) {
        case EndMatch::WIN:
            message = "You have won! Congratulations";
            break;
        case EndMatch::LOSE:
            message = "You have lost.";
            break;
        case EndMatch::SURRENDER_WIN:
            message = "You have won! Your opponent surrendered";
            break;
        case EndMatch::SURRENDER_LOSE:
            message = "You have surrendered. Your opponent thanks you.";
            break;
    }
    QMessageBox::information(this, "End of match", message, QMessageBox::Ok);
    parent_->setNextScreen(MAINMENUSTATE);

}

void MatchWidget::nextPlayer() {
    chosenWays.push_back(highlightedCases);
    highlightedCases.clear();
    refreshField();
}
<commit_msg>color for hiligthed case and chosen case set before GOALs and, ball.<commit_after>#include "matchwidget.h"
#include <iostream>
#include <cmath>

using namespace std;

MatchWidget::MatchWidget(Match * startingMatch, bool isGuest, int matchID, MainWindow * parent):
    QWidget(parent), parent_(parent), isGuest_(isGuest), matchID_(matchID) {
    //-----------------------MATCH INITIALISATION-----------------------
    currentMatch_ = startingMatch;

    //-------------------------SIZE SETTINGS---------------------------
    this->setFixedHeight(720);
    this->setFixedWidth(1280);

    //----------------------BACKGROUND SETTINGS---------------------------
    QVBoxLayout * layout = new QVBoxLayout;
    QLabel * image = new QLabel(this);
    image->setPixmap(QPixmap(ROOT_DIR + "/images/Quidditch_pitch_hogwarts.jpg"));
    layout->addWidget(image);

    //---------------------MAIN CONTAINER WIDGET---------------------------
    mainWidget = new QWidget(this);
    mainWidget->setFixedHeight(720);
    mainWidget->setFixedWidth(1280);
    QGridLayout * mainLayout = new QGridLayout(mainWidget);

    //------------------------SCORE SETTINGS--------------------------------
    int playerScore = currentMatch_->getScore()[0];
    ownScore = new QLabel("YOU : " + QString::fromStdString(std::to_string(playerScore)), mainWidget);
    ownScore->setFixedSize(250, 75);
    QFont font;
    font.setPointSize(17);
    ownScore->setStyleSheet(" font-weight: bold; font-size: 18pt; color : red;");
    ownScore->setAlignment(Qt::AlignBottom | Qt::AlignJustify);
    ownScore->setWordWrap(true);
    ownScore->setFont(font);
    ownScore->move(100, 50);
    ownScore->show();

    int otherScore = currentMatch_->getScore()[1];
    opponentScore = new QLabel("OPPONENT : " + QString::fromStdString(std::to_string(otherScore)), mainWidget);
    opponentScore->setFixedSize(250, 75);
    opponentScore->setAlignment(Qt::AlignBottom | Qt::AlignJustify);
    opponentScore->setStyleSheet(" font-weight: bold; font-size: 18pt; color : red;");
    opponentScore->setWordWrap(true);
    opponentScore->setFont(font);
    opponentScore->move(1000, 50);
    opponentScore->show();

    //---------------------FIELD CONTAINER WIDGET--------------------------
    fieldWidget  = new QFrame(mainWidget);

    //---------------------FIELD REPRESENTATION----------------------------

    fieldWidget->setFixedSize(QSize(LENGTH * 20, WIDTH * 17));
    QWidget * temp = new QWidget(fieldWidget);

    temp->setFixedSize((mainWidget->height() - WIDTH * 20) / 2, (mainWidget->width() - LENGTH * 20) / 2);
    mainLayout->setRowMinimumHeight(0, 100);
    mainLayout->addWidget(temp, 0, 0);
    mainLayout->addWidget(fieldWidget, 1, 1);

    turnEndButton = new QPushButton("End of turn", mainWidget);
    turnEndButton->setMinimumHeight(30);
    mainLayout->addWidget(turnEndButton, 2, 2);

    QPushButton * surrenderButton = new QPushButton("Surrender", mainWidget);
    surrenderButton->setMinimumHeight(30);
    mainLayout->addWidget(surrenderButton, 2, 3);

    //----------------------BUTTONS SIGNALS CONNECT-------------------------
    QObject::connect(turnEndButton, SIGNAL(clicked()), this, SLOT(endTurn()));
    QObject::connect(surrenderButton, SIGNAL(clicked()), this, SLOT(surrender()));

    //----------------------CUSTOM SIGNALS CONNECT-------------------------

    QObject::connect(parent_, SIGNAL(updateMatch(Match *)), this, SLOT(setCurrentMatch(Match *)));
    QObject::connect(parent_, SIGNAL(endMatch(int)), this, SLOT(endMatch(int)));

    //--------------------------START------------------------------
    currentMatch_->getGrid(grid_);
    label = 0;
    refreshField();

    mainWidget->show();

}

void MatchWidget::refreshField() {
    this->hide();
    ownScore->setText("YOU : " + QString::fromStdString(std::to_string(currentMatch_->getScore()[isGuest_])));
    opponentScore->setText("OPPONENT : " + QString::fromStdString(std::to_string(currentMatch_->getScore()[!isGuest_])));

    label = new QLabel(fieldWidget);
    QPixmap * pixmap = new QPixmap(LENGTH * 20, WIDTH * 17);
    pixmap->fill(Qt::transparent);

    QPainter painter(pixmap);
    Hexagon hexagon[WIDTH][LENGTH];
    QBrush * grass = new QBrush(QImage(ROOT_DIR + "/images/grass.jpg"));

    int xlabelDifference = 22;
    int ylabelDifference = 7;
    double x = 0;
    double y = 0;
    bool pair = true;
    bool highlighted;
    bool chosen;
    for (int i = 0; i < WIDTH; ++i) {
        for (int j = 0; j < LENGTH; ++j) {
            highlighted = false;
            chosen = false;
            hexagon[i][j].setX(x);
            hexagon[i][j].setY(y);
            hexagon[i][j].setCorners();

            x += 18;
            if (isCaseHighlighted(i, j)) {
                painter.setBrush(QBrush(QColor(71, 158, 158)));
                highlighted = true;
                painter.drawPolygon(hexagon[i][j].hexagon_);
            }
            else if (isInChosenWays(i, j)) {
                painter.setBrush(QBrush(QColor(85, 18, 201)));
                chosen = true;
                painter.drawPolygon(hexagon[i][j].hexagon_);
            }
            if (grid_[i][j].type == USABLE) {
                if (grid_[i][j].player != 0) {
                    if (!highlighted && !chosen) {
                        if (grid_[i][j].player->isInGuestTeam() == isGuest_) {
                            if(grid_[i][j].player->hasQuaffle()){
                                painter.setBrush(QBrush(QColor(0, 100, 0)));
                            }
                            else{
                                painter.setBrush(QBrush(Qt::blue));
                            }
                        }
                        else {
                            if(grid_[i][j].player->hasQuaffle()){
                                painter.setBrush(QBrush(QColor(255, 120, 31)));
                            }
                            else{
                                painter.setBrush(QBrush(Qt::red));
                            }
                        }
                    }
                    if (grid_[i][j].player->getRole() == KEEPER) {
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][KEEPER] = new QLabel("K", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][KEEPER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                    else if (grid_[i][j].player->getRole() == CHASER) {
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][CHASER] = new QLabel("C", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][CHASER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                    else if (grid_[i][j].player->getRole() == SEEKER) {
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][SEEKER] = new QLabel("S", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][SEEKER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                    else if (grid_[i][j].player->getRole() == BEATER) {
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][BEATER] = new QLabel("B", fieldWidget);
                        playerLabels_[grid_[i][j].player->isInGuestTeam()][BEATER]->move(x - xlabelDifference, y - ylabelDifference);
                    }
                }
                else if (grid_[i][j].ball != 0 && !highlighted && !chosen) {
                    string ballName = grid_[i][j].ball->getName();
                    if (ballName == "B") {
                        painter.setBrush(QBrush(Qt::black));
                    }
                    else if (ballName == "Q") {
                        painter.setBrush(QBrush(QColor(140, 52, 52)));
                    }
                    else { //ballName == "G"
                        painter.setBrush(QBrush(Qt::yellow));
                    }
                }
                else {
                    if (!highlighted && !chosen) {
                        painter.setBrush(*grass);
                    }
                }
                if (!highlighted && !chosen) {
                    painter.drawPolygon(hexagon[i][j].hexagon_);
                }
            }
            else if (grid_[i][j].type == GOAL && !highlighted && !chosen) {
                painter.setBrush(QBrush(QColor(64, 64, 72)));
                painter.drawPolygon(hexagon[i][j].hexagon_);
            }
        }
        y += 15;
        if (pair) {
            x = 35;
        }
        else {
            x = 26;
        }
        pair = !pair;
    }
    label->setPixmap(*pixmap);

    this->show();
}

bool MatchWidget::isInChosenWays(unsigned x, unsigned y) {
    for (int i = 0; i < chosenWays.size(); ++i) {
        for (int j = 0; j < chosenWays[i].size(); ++j) {
            if ((chosenWays[i][j].x == x) && (chosenWays[i][j].y == y)) {
                return true;
            }
        }
    }
    return false;
}

bool MatchWidget::isCaseHighlighted(unsigned a, unsigned b) {
    for (size_t i = 0; i < highlightedCases.size(); ++i) {
        if ((highlightedCases[i].x == a) && (highlightedCases[i].y == b)) {
            return true;
        }
    }
    return false;
}

MatchWidget::~MatchWidget() {}

void MatchWidget::setCurrentMatch(Match * match) {
    turnEndButton->setEnabled(true);
    turnEndButton->setStyleSheet("color : white;");
    currentMatch_ = match;
    Case grid[WIDTH][LENGTH];
    currentMatch_->getGrid(grid);
    for (int i = 0; i < WIDTH; ++i) {
        for (int j = 0; j < LENGTH; ++j) {
            grid_[i][j] = grid[i][j];
        }
    }

    refreshField();
}

Position MatchWidget::getCase(QMouseEvent * event) {
    int row = 0;
    int column = 0;
    double hexagonHeight = 18;
    double hexagonWidth = 15;
    double halfHeight = hexagonHeight / 2;
    int startHeight = 103;
    int startWidth = 144;

    if ((event->x() > startHeight) && (event->x() < 1200)) {
        if ((event->y() > startWidth) && (event->y() < 580)) {

            // These will represent which box the mouse is in, not which hexagon!
            row = (event->y() - startWidth) / hexagonWidth;
            bool rowIsOdd = row % 2 == 0;

            // Is the row an even number?
            if (rowIsOdd) {
                column = ((event->x() - startHeight) / hexagonHeight);
            }
            else {
                column = ((event->x() - startHeight + halfHeight) / hexagonHeight);
            }
        }
    }
    Position mouseCase;
    mouseCase.x = row + 1;
    mouseCase.y = column;
    return mouseCase;
}

void MatchWidget::endTurn() {
    turnEndButton->setDisabled(true);
    turnEndButton->setStyleSheet("color : black;");
    sviews::endTurn(parent_->getSocket(), chosenWays);
    chosenWays.clear();

}

void MatchWidget::surrender() {
    sviews::surrenders(parent_->getSocket(), matchID_);

}

void MatchWidget::mousePressEvent(QMouseEvent * event) {
    if (event->button() == Qt::RightButton) {
        highlightedCases.clear();
        refreshField();
    }
    else {
        Position clickedCase = getCase(event);
        if (highlightedCases.empty()) {
            int i = clickedCase.x;
            int j = clickedCase.y;
            if ((grid_[i][j].player != 0) && (grid_[i][j].player->isInGuestTeam() == isGuest_)) {
                highlightedCases.push_back(clickedCase);
            }
        }
        else {
            if (isCloseCase(clickedCase, highlightedCases[highlightedCases.size() - 1], 0)) {
                highlightedCases.push_back(clickedCase);
            }
            else if (highlightedCases[highlightedCases.size() - 1] == clickedCase) {
                emit this->nextPlayer();
            }
        }
        refreshField();
    }
}

void MatchWidget::endMatch(int signal) {
    QString message;
    switch (signal) {
        case EndMatch::WIN:
            message = "You have won! Congratulations";
            break;
        case EndMatch::LOSE:
            message = "You have lost.";
            break;
        case EndMatch::SURRENDER_WIN:
            message = "You have won! Your opponent surrendered";
            break;
        case EndMatch::SURRENDER_LOSE:
            message = "You have surrendered. Your opponent thanks you.";
            break;
    }
    QMessageBox::information(this, "End of match", message, QMessageBox::Ok);
    parent_->setNextScreen(MAINMENUSTATE);

}

void MatchWidget::nextPlayer() {
    chosenWays.push_back(highlightedCases);
    highlightedCases.clear();
    refreshField();
}
<|endoftext|>


<commit_before>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"

namespace furfurylic {
namespace commata {
namespace detail {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// To define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end namespace detail

class text_error_info;

class text_error :
    public std::exception, public detail::npos_impl<std::size_t>
{
    std::shared_ptr<std::string> what_;
    std::pair<std::size_t, std::size_t> physical_position_;

public:
    template <class T,
        class = std::enable_if_t<std::is_constructible<std::string, T>::value>>
    explicit text_error(T&& what_arg) :
        what_(std::make_shared<std::string>(std::forward<T>(what_arg))),
        physical_position_(npos, npos)
    {}

    // Copy/move ctors and copy/move assignment ops are explicitly defined
    // so that they are noexcept

    text_error(const text_error& other) noexcept :
        std::exception(other),
        what_(other.what_),
        physical_position_(other.physical_position_)
        // According to C++14 20.3.2 (1), pair's copy ctor is noexcept
    {}

    text_error(text_error&& other) noexcept :
        std::exception(std::move(other)),
        what_(std::move(other.what_)),
        physical_position_(other.physical_position_)
        // ditto
    {}

    text_error& operator=(const text_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        physical_position_ = other.physical_position_;
        // According to C++14 20.3.2 (1), pair's assignments are noexcept
        return *this;
    }

    text_error& operator=(text_error&& other) noexcept
    {
        std::exception::operator=(std::move(other));
        what_ = std::move(other.what_);
        physical_position_ = other.physical_position_;
        // ditto
        return *this;
    }

    const char* what() const noexcept override
    {
        return what_->c_str(); // std::string::c_str is noexcept
    }

    void set_physical_position(std::size_t line = npos, std::size_t col = npos)
    {
        physical_position_ = std::make_pair(line, col);
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        // std::make_pair<std::size_t, std::size_t> shall not throw exceptions
        return (physical_position_ != std::make_pair(npos, npos)) ?
            &physical_position_ : nullptr;
    }

    text_error_info info() const noexcept;
};

namespace detail {

// Prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::streamsize print_pos(char (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::snprintf(s, N, "%zu", pos + 1) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

template <std::size_t N>
std::streamsize print_pos(wchar_t (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::swprintf(s, N, L"%zu", pos + 1) :
        std::swprintf(s, N, L"n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

} // end namespace detail

class text_error_info
{
    const text_error* ex_;

public:
    explicit text_error_info(const text_error& ex) noexcept :
        ex_(&ex)
    {}

    const text_error& error() const noexcept
    {
        return *ex_;
    }
};

template <class Tr>
std::basic_ostream<char, Tr>& operator<<(
    std::basic_ostream<char, Tr>& os, const text_error_info& i)
{
    if (const auto p = i.error().get_physical_position()) {
        // line
        char l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        char c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        // what
        const auto w = i.error().what();
        const auto w_len = static_cast<std::streamsize>(std::strlen(w));

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    if ((sb->sputn(w, w_len) != w_len)
                     || (sb->sputn("; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn("Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else {
        return os << i.error().what();
    }
}

template <class Tr>
std::basic_ostream<wchar_t, Tr>& operator<<(
    std::basic_ostream<wchar_t, Tr>& os, const text_error_info& i)
{
    // Count the wide characters in what, which may be an NTMBS
    auto w_raw = i.error().what();
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
    auto w_len = static_cast<std::streamsize>(std::mbstowcs(0, w_raw, 0));
#ifdef _MSC_VER
#pragma warning(pop)
#endif
    if (w_len == -1) {
        // Conversion failed
        w_raw = "";
        w_len = 0;
    }

    if (const auto p = i.error().get_physical_position()) {
        // line
        wchar_t l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        wchar_t c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w_raw, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    std::unique_ptr<wchar_t[]> w(
                        new wchar_t[w_len + 1]);                    // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                    std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                    w[w_len] = L'\0';   // maybe not required
                    if ((sb->sputn(w.get(), w_len) != w_len)
                     || (sb->sputn(L"; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn(L"Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(L" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else if (w_len > 0) {
        return detail::formatted_output(os, w_len,
            [w_raw, &w_len]
            (auto* sb) {
                std::unique_ptr<wchar_t[]> w(
                    new wchar_t[w_len + 1]);                        // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                w[w_len] = L'\0';   // maybe not required
                return sb->sputn(w.get(), w_len) == w_len;
            });

    } else {
        return os;
    }
}

inline text_error_info text_error::info() const noexcept
{
    return text_error_info(*this);
}

inline std::string to_string(const text_error_info& i)
{
    std::ostringstream s;
    s << i;
    return s.str();
}

inline std::wstring to_wstring(const text_error_info& i)
{
    std::wostringstream s;
    s << i;
    return s.str();
}

}}

#endif
<commit_msg>Swap the definition order of text_error and text_error_info<commit_after>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"

namespace furfurylic {
namespace commata {
namespace detail {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// To define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end namespace detail

class text_error;

class text_error_info
{
    const text_error* ex_;

public:
    explicit text_error_info(const text_error& ex) noexcept :
        ex_(&ex)
    {}

    const text_error& error() const noexcept
    {
        return *ex_;
    }
};

class text_error :
    public std::exception, public detail::npos_impl<std::size_t>
{
    std::shared_ptr<std::string> what_;
    std::pair<std::size_t, std::size_t> physical_position_;

public:
    template <class T,
        class = std::enable_if_t<std::is_constructible<std::string, T>::value>>
    explicit text_error(T&& what_arg) :
        what_(std::make_shared<std::string>(std::forward<T>(what_arg))),
        physical_position_(npos, npos)
    {}

    // Copy/move ctors and copy/move assignment ops are explicitly defined
    // so that they are noexcept

    text_error(const text_error& other) noexcept :
        std::exception(other),
        what_(other.what_),
        physical_position_(other.physical_position_)
        // According to C++14 20.3.2 (1), pair's copy ctor is noexcept
    {}

    text_error(text_error&& other) noexcept :
        std::exception(std::move(other)),
        what_(std::move(other.what_)),
        physical_position_(other.physical_position_)
        // ditto
    {}

    text_error& operator=(const text_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        physical_position_ = other.physical_position_;
        // According to C++14 20.3.2 (1), pair's assignments are noexcept
        return *this;
    }

    text_error& operator=(text_error&& other) noexcept
    {
        std::exception::operator=(std::move(other));
        what_ = std::move(other.what_);
        physical_position_ = other.physical_position_;
        // ditto
        return *this;
    }

    const char* what() const noexcept override
    {
        return what_->c_str(); // std::string::c_str is noexcept
    }

    void set_physical_position(std::size_t line = npos, std::size_t col = npos)
    {
        physical_position_ = std::make_pair(line, col);
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        // std::make_pair<std::size_t, std::size_t> shall not throw exceptions
        return (physical_position_ != std::make_pair(npos, npos)) ?
            &physical_position_ : nullptr;
    }

    text_error_info info() const noexcept
    {
        return text_error_info(*this);
    }
};

namespace detail {

// Prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::streamsize print_pos(char (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::snprintf(s, N, "%zu", pos + 1) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

template <std::size_t N>
std::streamsize print_pos(wchar_t (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::swprintf(s, N, L"%zu", pos + 1) :
        std::swprintf(s, N, L"n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

} // end namespace detail

template <class Tr>
std::basic_ostream<char, Tr>& operator<<(
    std::basic_ostream<char, Tr>& os, const text_error_info& i)
{
    if (const auto p = i.error().get_physical_position()) {
        // line
        char l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        char c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        // what
        const auto w = i.error().what();
        const auto w_len = static_cast<std::streamsize>(std::strlen(w));

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    if ((sb->sputn(w, w_len) != w_len)
                     || (sb->sputn("; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn("Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else {
        return os << i.error().what();
    }
}

template <class Tr>
std::basic_ostream<wchar_t, Tr>& operator<<(
    std::basic_ostream<wchar_t, Tr>& os, const text_error_info& i)
{
    // Count the wide characters in what, which may be an NTMBS
    auto w_raw = i.error().what();
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
    auto w_len = static_cast<std::streamsize>(std::mbstowcs(0, w_raw, 0));
#ifdef _MSC_VER
#pragma warning(pop)
#endif
    if (w_len == -1) {
        // Conversion failed
        w_raw = "";
        w_len = 0;
    }

    if (const auto p = i.error().get_physical_position()) {
        // line
        wchar_t l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        wchar_t c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w_raw, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    std::unique_ptr<wchar_t[]> w(
                        new wchar_t[w_len + 1]);                    // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                    std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                    w[w_len] = L'\0';   // maybe not required
                    if ((sb->sputn(w.get(), w_len) != w_len)
                     || (sb->sputn(L"; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn(L"Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(L" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else if (w_len > 0) {
        return detail::formatted_output(os, w_len,
            [w_raw, &w_len]
            (auto* sb) {
                std::unique_ptr<wchar_t[]> w(
                    new wchar_t[w_len + 1]);                        // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                w[w_len] = L'\0';   // maybe not required
                return sb->sputn(w.get(), w_len) == w_len;
            });

    } else {
        return os;
    }
}

inline std::string to_string(const text_error_info& i)
{
    std::ostringstream s;
    s << i;
    return s.str();
}

inline std::wstring to_wstring(const text_error_info& i)
{
    std::wostringstream s;
    s << i;
    return s.str();
}

}}

#endif
<|endoftext|>