<commit_before>/*
Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
All rights reserved.

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

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

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

*/

#ifndef LIBTORRENT_BUFFER_HPP
#define LIBTORRENT_BUFFER_HPP

//#define TORRENT_BUFFER_DEBUG

#include "libtorrent/invariant_check.hpp"
#include <memory>

namespace libtorrent {

class buffer
{
public:
    struct interval
    {
       interval(char* begin, char* end)
          : begin(begin)
          , end(end)
        {}

        char operator[](int index) const
        {
            assert(begin + index < end);
            return begin[index];
        }

        int left() const { assert(end > begin); return end - begin; }

        char* begin;
        char* end;
    };

    struct const_interval
    {
       const_interval(char const* begin, char const* end)
          : begin(begin)
          , end(end)
        {}

        char operator[](int index) const
        {
            assert(begin + index < end);
            return begin[index];
        }

        int left() const { assert(end > begin); return end - begin; }

        char const* begin;
        char const* end;
    };

    typedef std::pair<const_interval, const_interval> interval_type;

    buffer(std::size_t n = 0);
    ~buffer();

    interval allocate(std::size_t n);
    void insert(char const* first, char const* last);
    void erase(std::size_t n);
    std::size_t size() const;
    std::size_t capacity() const;
    void reserve(std::size_t n);
    interval_type data() const;
    bool empty() const;

    std::size_t space_left() const;

    char const* raw_data() const
    {
        return m_first;
    }

#ifndef NDEBUG
    void check_invariant() const;
#endif

private:
    char* m_first;
    char* m_last;
    char* m_write_cursor;
    char* m_read_cursor;
    char* m_read_end;
    bool m_empty;
#ifdef TORRENT_BUFFER_DEBUG
    mutable std::vector<char> m_debug;
    mutable int m_pending_copy;
#endif
};

inline buffer::buffer(std::size_t n)
	: m_first((char*)::operator new(n))
	, m_last(m_first + n)
	, m_write_cursor(m_first)
	, m_read_cursor(m_first)
	, m_read_end(m_last)
	, m_empty(true)
{
#ifdef TORRENT_BUFFER_DEBUG
	m_pending_copy = 0;
#endif
}

inline buffer::~buffer()
{
    ::operator delete (m_first);
}

inline buffer::interval buffer::allocate(std::size_t n)
{
	assert(m_read_cursor <= m_read_end || m_empty);

	INVARIANT_CHECK;

#ifdef TORRENT_BUFFER_DEBUG
	if (m_pending_copy)
	{
		std::copy(m_write_cursor - m_pending_copy, m_write_cursor
			, m_debug.end() - m_pending_copy);
		m_pending_copy = 0;
	}
	m_debug.resize(m_debug.size() + n);
	m_pending_copy = n;
#endif
	if (m_read_cursor < m_write_cursor || m_empty)
	{
	// ..R***W..
		if (m_last - m_write_cursor >= (std::ptrdiff_t)n)
		{
			interval ret(m_write_cursor, m_write_cursor + n);
			m_write_cursor += n;
			m_read_end = m_write_cursor;
			assert(m_read_cursor <= m_read_end);
			if (n) m_empty = false;
			return ret;
		}

		if (m_read_cursor - m_first >= (std::ptrdiff_t)n)
		{
			m_read_end = m_write_cursor;
			interval ret(m_first, m_first + n);
			m_write_cursor = m_first + n;
			assert(m_read_cursor <= m_read_end);
			if (n) m_empty = false;
			return ret;
		}

		reserve(capacity() + n - (m_last - m_write_cursor));
		assert(m_last - m_write_cursor >= (std::ptrdiff_t)n);
		interval ret(m_write_cursor, m_write_cursor + n);
		m_write_cursor += n;
		m_read_end = m_write_cursor;
		if (n) m_empty = false;
		assert(m_read_cursor <= m_read_end);
		return ret;

	}
	//**W...R**
	if (m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n)
	{
		interval ret(m_write_cursor, m_write_cursor + n);
		m_write_cursor += n;
		if (n) m_empty = false;
		return ret;
	}
	reserve(capacity() + n - (m_read_cursor - m_write_cursor));
	assert(m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n);
	interval ret(m_write_cursor, m_write_cursor + n);
	m_write_cursor += n;
	if (n) m_empty = false;
	return ret;
}

inline void buffer::insert(char const* first, char const* last)
{
    INVARIANT_CHECK;

    std::size_t n = last - first;

#ifdef TORRENT_BUFFER_DEBUG
	if (m_pending_copy)
	{
		std::copy(m_write_cursor - m_pending_copy, m_write_cursor
			, m_debug.end() - m_pending_copy);
		m_pending_copy = 0;
	}
	m_debug.insert(m_debug.end(), first, last);
#endif

    if (space_left() < n)
    {
        reserve(capacity() + n);
    }

    m_empty = false;

    char const* end = (m_last - m_write_cursor) < (std::ptrdiff_t)n ?
        m_last : m_write_cursor + n;

    std::size_t copied = end - m_write_cursor;
    std::memcpy(m_write_cursor, first, copied);

    m_write_cursor += copied;
	 if (m_write_cursor > m_read_end) m_read_end = m_write_cursor;
    first += copied;
    n -= copied;

    if (n == 0) return;

	 assert(m_write_cursor == m_last);
    m_write_cursor = m_first;

    memcpy(m_write_cursor, first, n);
    m_write_cursor += n;
}

inline void buffer::erase(std::size_t n)
{
	INVARIANT_CHECK;

	if (n == 0) return;
	assert(!m_empty);

#ifndef NDEBUG
	int prev_size = size();
#endif
	assert(m_read_cursor <= m_read_end);
	m_read_cursor += n;
	if (m_read_cursor > m_read_end)
	{
		m_read_cursor = m_first + (m_read_cursor - m_read_end);
		assert(m_read_cursor <= m_write_cursor);
	}

	m_empty = m_read_cursor == m_write_cursor;

	assert(prev_size - n == size());

#ifdef TORRENT_BUFFER_DEBUG
	m_debug.erase(m_debug.begin(), m_debug.begin() + n);
#endif
}

inline std::size_t buffer::size() const
{
    // ...R***W.
    if (m_read_cursor < m_write_cursor)
    {
        return m_write_cursor - m_read_cursor;
    }
    // ***W..R*
    else
    {
        if (m_empty) return 0;
        return (m_write_cursor - m_first) + (m_read_end - m_read_cursor);
    }
}

inline std::size_t buffer::capacity() const
{
    return m_last - m_first;
}

inline void buffer::reserve(std::size_t size)
{
    std::size_t n = (std::size_t)(capacity() * 1.f);
    if (n < size) n = size;

    char* buf = (char*)::operator new(n);
    char* old = m_first;

    if (m_read_cursor < m_write_cursor)
    {
    // ...R***W.<>.
        std::memcpy(
            buf + (m_read_cursor - m_first)
          , m_read_cursor
          , m_write_cursor - m_read_cursor
        );

        m_write_cursor = buf + (m_write_cursor - m_first);
        m_read_cursor = buf + (m_read_cursor - m_first);
		  m_read_end = m_write_cursor;
        m_first = buf;
        m_last = buf + n;
    }
    else
    {
    // **W..<>.R**
        std::size_t skip = n - (m_last - m_first);

        std::memcpy(buf, m_first, m_write_cursor - m_first);
        std::memcpy(
            buf + (m_read_cursor - m_first) + skip
          , m_read_cursor
          , m_last - m_read_cursor
        );

        m_write_cursor = buf + (m_write_cursor - m_first);

        if (!m_empty)
		  {
            m_read_cursor = buf + (m_read_cursor - m_first) + skip;
            m_read_end = buf + (m_read_end - m_first) + skip;
		  }
        else
		  {
            m_read_cursor = m_write_cursor;
				m_read_end = m_write_cursor;
		  }

        m_first = buf;
        m_last = buf + n;
    }

    ::operator delete (old);
}

#ifndef NDEBUG
inline void buffer::check_invariant() const
{
	assert(m_read_end >= m_read_cursor);
	assert(m_last >= m_read_cursor);
	assert(m_last >= m_write_cursor);
	assert(m_last >= m_first);
	assert(m_first <= m_read_cursor);
	assert(m_first <= m_write_cursor);
#ifdef TORRENT_BUFFER_DEBUG
	int a = m_debug.size();
	int b = size();
	(void)a;
	(void)b;
	assert(m_debug.size() == size());
#endif
}
#endif

inline buffer::interval_type buffer::data() const
{
	INVARIANT_CHECK;

#ifdef TORRENT_BUFFER_DEBUG
	if (m_pending_copy)
	{
		std::copy(m_write_cursor - m_pending_copy, m_write_cursor
			, m_debug.end() - m_pending_copy);
		m_pending_copy = 0;
	}
#endif

    // ...R***W.
    if (m_read_cursor < m_write_cursor)
    {
#ifdef TORRENT_BUFFER_DEBUG
        assert(m_debug.size() == size());
        assert(std::equal(m_debug.begin(), m_debug.end(), m_read_cursor));
#endif
        return interval_type(
            const_interval(m_read_cursor, m_write_cursor)
          , const_interval(m_last, m_last)
        );
    }
    // **W...R**
    else
    {
        if (m_read_cursor == m_read_end)
		  {
#ifdef TORRENT_BUFFER_DEBUG
	        assert(m_debug.size() == size());
	        assert(std::equal(m_debug.begin(), m_debug.end(), m_first));
#endif

            return interval_type(
                const_interval(m_first, m_write_cursor)
                , const_interval(m_last, m_last));
		  }
#ifdef TORRENT_BUFFER_DEBUG
        assert(m_debug.size() == size());
        assert(std::equal(m_debug.begin(), m_debug.begin() + (m_read_end
            - m_read_cursor), m_read_cursor));
        assert(std::equal(m_debug.begin() + (m_read_end - m_read_cursor), m_debug.end()
            , m_first));
#endif

        assert(m_read_cursor <= m_read_end || m_empty);
        return interval_type(
            const_interval(m_read_cursor, m_read_end)
          , const_interval(m_first, m_write_cursor)
        );
    }
}

inline bool buffer::empty() const
{
    return m_empty;
}

inline std::size_t buffer::space_left() const
{
    if (m_empty) return m_last - m_first;

    // ...R***W.
    if (m_read_cursor < m_write_cursor)
    {
        return (m_last - m_write_cursor) + (m_read_cursor - m_first);
    }
    // ***W..R*
    else
    {
        return m_read_cursor - m_write_cursor;
    }
}

}

#endif // LIBTORRENT_BUFFER_HPP

<commit_msg>fixed incorrect assert<commit_after>/*
Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
All rights reserved.

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

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

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

*/

#ifndef LIBTORRENT_BUFFER_HPP
#define LIBTORRENT_BUFFER_HPP

//#define TORRENT_BUFFER_DEBUG

#include "libtorrent/invariant_check.hpp"
#include <memory>

namespace libtorrent {

class buffer
{
public:
    struct interval
    {
       interval(char* begin, char* end)
          : begin(begin)
          , end(end)
        {}

        char operator[](int index) const
        {
            assert(begin + index < end);
            return begin[index];
        }

        int left() const { assert(end >= begin); return end - begin; }

        char* begin;
        char* end;
    };

    struct const_interval
    {
       const_interval(char const* begin, char const* end)
          : begin(begin)
          , end(end)
        {}

        char operator[](int index) const
        {
            assert(begin + index < end);
            return begin[index];
        }

        int left() const { assert(end >= begin); return end - begin; }

        char const* begin;
        char const* end;
    };

    typedef std::pair<const_interval, const_interval> interval_type;

    buffer(std::size_t n = 0);
    ~buffer();

    interval allocate(std::size_t n);
    void insert(char const* first, char const* last);
    void erase(std::size_t n);
    std::size_t size() const;
    std::size_t capacity() const;
    void reserve(std::size_t n);
    interval_type data() const;
    bool empty() const;

    std::size_t space_left() const;

    char const* raw_data() const
    {
        return m_first;
    }

#ifndef NDEBUG
    void check_invariant() const;
#endif

private:
    char* m_first;
    char* m_last;
    char* m_write_cursor;
    char* m_read_cursor;
    char* m_read_end;
    bool m_empty;
#ifdef TORRENT_BUFFER_DEBUG
    mutable std::vector<char> m_debug;
    mutable int m_pending_copy;
#endif
};

inline buffer::buffer(std::size_t n)
	: m_first((char*)::operator new(n))
	, m_last(m_first + n)
	, m_write_cursor(m_first)
	, m_read_cursor(m_first)
	, m_read_end(m_last)
	, m_empty(true)
{
#ifdef TORRENT_BUFFER_DEBUG
	m_pending_copy = 0;
#endif
}

inline buffer::~buffer()
{
    ::operator delete (m_first);
}

inline buffer::interval buffer::allocate(std::size_t n)
{
	assert(m_read_cursor <= m_read_end || m_empty);

	INVARIANT_CHECK;

#ifdef TORRENT_BUFFER_DEBUG
	if (m_pending_copy)
	{
		std::copy(m_write_cursor - m_pending_copy, m_write_cursor
			, m_debug.end() - m_pending_copy);
		m_pending_copy = 0;
	}
	m_debug.resize(m_debug.size() + n);
	m_pending_copy = n;
#endif
	if (m_read_cursor < m_write_cursor || m_empty)
	{
	// ..R***W..
		if (m_last - m_write_cursor >= (std::ptrdiff_t)n)
		{
			interval ret(m_write_cursor, m_write_cursor + n);
			m_write_cursor += n;
			m_read_end = m_write_cursor;
			assert(m_read_cursor <= m_read_end);
			if (n) m_empty = false;
			return ret;
		}

		if (m_read_cursor - m_first >= (std::ptrdiff_t)n)
		{
			m_read_end = m_write_cursor;
			interval ret(m_first, m_first + n);
			m_write_cursor = m_first + n;
			assert(m_read_cursor <= m_read_end);
			if (n) m_empty = false;
			return ret;
		}

		reserve(capacity() + n - (m_last - m_write_cursor));
		assert(m_last - m_write_cursor >= (std::ptrdiff_t)n);
		interval ret(m_write_cursor, m_write_cursor + n);
		m_write_cursor += n;
		m_read_end = m_write_cursor;
		if (n) m_empty = false;
		assert(m_read_cursor <= m_read_end);
		return ret;

	}
	//**W...R**
	if (m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n)
	{
		interval ret(m_write_cursor, m_write_cursor + n);
		m_write_cursor += n;
		if (n) m_empty = false;
		return ret;
	}
	reserve(capacity() + n - (m_read_cursor - m_write_cursor));
	assert(m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n);
	interval ret(m_write_cursor, m_write_cursor + n);
	m_write_cursor += n;
	if (n) m_empty = false;
	return ret;
}

inline void buffer::insert(char const* first, char const* last)
{
    INVARIANT_CHECK;

    std::size_t n = last - first;

#ifdef TORRENT_BUFFER_DEBUG
	if (m_pending_copy)
	{
		std::copy(m_write_cursor - m_pending_copy, m_write_cursor
			, m_debug.end() - m_pending_copy);
		m_pending_copy = 0;
	}
	m_debug.insert(m_debug.end(), first, last);
#endif

    if (space_left() < n)
    {
        reserve(capacity() + n);
    }

    m_empty = false;

    char const* end = (m_last - m_write_cursor) < (std::ptrdiff_t)n ?
        m_last : m_write_cursor + n;

    std::size_t copied = end - m_write_cursor;
    std::memcpy(m_write_cursor, first, copied);

    m_write_cursor += copied;
	 if (m_write_cursor > m_read_end) m_read_end = m_write_cursor;
    first += copied;
    n -= copied;

    if (n == 0) return;

	 assert(m_write_cursor == m_last);
    m_write_cursor = m_first;

    memcpy(m_write_cursor, first, n);
    m_write_cursor += n;
}

inline void buffer::erase(std::size_t n)
{
	INVARIANT_CHECK;

	if (n == 0) return;
	assert(!m_empty);

#ifndef NDEBUG
	int prev_size = size();
#endif
	assert(m_read_cursor <= m_read_end);
	m_read_cursor += n;
	if (m_read_cursor > m_read_end)
	{
		m_read_cursor = m_first + (m_read_cursor - m_read_end);
		assert(m_read_cursor <= m_write_cursor);
	}

	m_empty = m_read_cursor == m_write_cursor;

	assert(prev_size - n == size());

#ifdef TORRENT_BUFFER_DEBUG
	m_debug.erase(m_debug.begin(), m_debug.begin() + n);
#endif
}

inline std::size_t buffer::size() const
{
    // ...R***W.
    if (m_read_cursor < m_write_cursor)
    {
        return m_write_cursor - m_read_cursor;
    }
    // ***W..R*
    else
    {
        if (m_empty) return 0;
        return (m_write_cursor - m_first) + (m_read_end - m_read_cursor);
    }
}

inline std::size_t buffer::capacity() const
{
    return m_last - m_first;
}

inline void buffer::reserve(std::size_t size)
{
    std::size_t n = (std::size_t)(capacity() * 1.f);
    if (n < size) n = size;

    char* buf = (char*)::operator new(n);
    char* old = m_first;

    if (m_read_cursor < m_write_cursor)
    {
    // ...R***W.<>.
        std::memcpy(
            buf + (m_read_cursor - m_first)
          , m_read_cursor
          , m_write_cursor - m_read_cursor
        );

        m_write_cursor = buf + (m_write_cursor - m_first);
        m_read_cursor = buf + (m_read_cursor - m_first);
		  m_read_end = m_write_cursor;
        m_first = buf;
        m_last = buf + n;
    }
    else
    {
    // **W..<>.R**
        std::size_t skip = n - (m_last - m_first);

        std::memcpy(buf, m_first, m_write_cursor - m_first);
        std::memcpy(
            buf + (m_read_cursor - m_first) + skip
          , m_read_cursor
          , m_last - m_read_cursor
        );

        m_write_cursor = buf + (m_write_cursor - m_first);

        if (!m_empty)
		  {
            m_read_cursor = buf + (m_read_cursor - m_first) + skip;
            m_read_end = buf + (m_read_end - m_first) + skip;
		  }
        else
		  {
            m_read_cursor = m_write_cursor;
				m_read_end = m_write_cursor;
		  }

        m_first = buf;
        m_last = buf + n;
    }

    ::operator delete (old);
}

#ifndef NDEBUG
inline void buffer::check_invariant() const
{
	assert(m_read_end >= m_read_cursor);
	assert(m_last >= m_read_cursor);
	assert(m_last >= m_write_cursor);
	assert(m_last >= m_first);
	assert(m_first <= m_read_cursor);
	assert(m_first <= m_write_cursor);
#ifdef TORRENT_BUFFER_DEBUG
	int a = m_debug.size();
	int b = size();
	(void)a;
	(void)b;
	assert(m_debug.size() == size());
#endif
}
#endif

inline buffer::interval_type buffer::data() const
{
	INVARIANT_CHECK;

#ifdef TORRENT_BUFFER_DEBUG
	if (m_pending_copy)
	{
		std::copy(m_write_cursor - m_pending_copy, m_write_cursor
			, m_debug.end() - m_pending_copy);
		m_pending_copy = 0;
	}
#endif

    // ...R***W.
    if (m_read_cursor < m_write_cursor)
    {
#ifdef TORRENT_BUFFER_DEBUG
        assert(m_debug.size() == size());
        assert(std::equal(m_debug.begin(), m_debug.end(), m_read_cursor));
#endif
        return interval_type(
            const_interval(m_read_cursor, m_write_cursor)
          , const_interval(m_last, m_last)
        );
    }
    // **W...R**
    else
    {
        if (m_read_cursor == m_read_end)
		  {
#ifdef TORRENT_BUFFER_DEBUG
	        assert(m_debug.size() == size());
	        assert(std::equal(m_debug.begin(), m_debug.end(), m_first));
#endif

            return interval_type(
                const_interval(m_first, m_write_cursor)
                , const_interval(m_last, m_last));
		  }
#ifdef TORRENT_BUFFER_DEBUG
        assert(m_debug.size() == size());
        assert(std::equal(m_debug.begin(), m_debug.begin() + (m_read_end
            - m_read_cursor), m_read_cursor));
        assert(std::equal(m_debug.begin() + (m_read_end - m_read_cursor), m_debug.end()
            , m_first));
#endif

        assert(m_read_cursor <= m_read_end || m_empty);
        return interval_type(
            const_interval(m_read_cursor, m_read_end)
          , const_interval(m_first, m_write_cursor)
        );
    }
}

inline bool buffer::empty() const
{
    return m_empty;
}

inline std::size_t buffer::space_left() const
{
    if (m_empty) return m_last - m_first;

    // ...R***W.
    if (m_read_cursor < m_write_cursor)
    {
        return (m_last - m_write_cursor) + (m_read_cursor - m_first);
    }
    // ***W..R*
    else
    {
        return m_read_cursor - m_write_cursor;
    }
}

}

#endif // LIBTORRENT_BUFFER_HPP

<|endoftext|>


<commit_before>/*

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

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

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

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

*/

#ifndef TORRENT_CONFIG_HPP_INCLUDED
#define TORRENT_CONFIG_HPP_INCLUDED

#include <boost/config.hpp>
#include <boost/version.hpp>
#include <stdio.h> // for snprintf

#ifndef WIN32
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif

#ifndef PRId64
#ifdef _WIN32
#define PRId64 "I64d"
#else
#define PRId64 "lld"
#endif
#endif

#if defined(__GNUC__) && __GNUC__ >= 4

#define TORRENT_DEPRECATED __attribute__ ((deprecated))

# if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __attribute__ ((visibility("default")))
# else
#  define TORRENT_EXPORT
# endif

#elif defined(__GNUC__)

# define TORRENT_EXPORT

#elif defined(BOOST_MSVC)

#pragma warning(disable: 4258)
#pragma warning(disable: 4251)

# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# else
#  define TORRENT_EXPORT
# endif

#else
# define TORRENT_EXPORT
#endif

#ifndef TORRENT_DEPRECATED
#define TORRENT_DEPRECATED
#endif

// set up defines for target environments
#if (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \
	|| defined __FreeBSD_kernel__
#define TORRENT_BSD
#elif defined __linux__
#define TORRENT_LINUX
#elif defined WIN32
#define TORRENT_WINDOWS
#elif defined sun || defined __sun
#define TORRENT_SOLARIS
#else
#warning unkown OS, assuming BSD
#define TORRENT_BSD
#endif

#define TORRENT_USE_IPV6 1
#define TORRENT_USE_MLOCK 1
#define TORRENT_USE_READV 1
#define TORRENT_USE_WRITEV 1
#define TORRENT_USE_IOSTREAM 1

// should wpath or path be used?
#if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY \
	&& BOOST_VERSION >= 103400 && !defined __APPLE__
#define TORRENT_USE_WPATH 1
#else
#define TORRENT_USE_WPATH 0
#endif

#ifdef TORRENT_WINDOWS
#include <stdarg.h>
// this is the maximum number of characters in a
// path element / filename on windows
#define NAME_MAX 255
inline int snprintf(char* buf, int len, char const* fmt, ...)
{
	va_list lp;
	va_start(lp, fmt);
	return vsnprintf_s(buf, len, _TRUNCATE, fmt, lp);
}
#define strtoll _strtoi64
#endif

#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) && !defined (TORRENT_UPNP_LOGGING)
#define TORRENT_UPNP_LOGGING
#endif

#if !TORRENT_USE_WPATH && defined TORRENT_LINUX
// libiconv presnce, not implemented yet
#define TORRENT_USE_LOCALE_FILENAMES 1
#else
#define TORRENT_USE_LOCALE_FILENAMES 0
#endif

#if !defined(TORRENT_READ_HANDLER_MAX_SIZE)
# define TORRENT_READ_HANDLER_MAX_SIZE 256
#endif

#if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE)
# define TORRENT_WRITE_HANDLER_MAX_SIZE 256
#endif

// determine what timer implementation we can use

#if defined(__MACH__)
#define TORRENT_USE_ABSOLUTE_TIME 1
#elif defined(_WIN32)
#define TORRENT_USE_QUERY_PERFORMANCE_TIMER 1
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
#define TORRENT_USE_CLOCK_GETTIME 1
#else
#define TORRENT_USE_BOOST_DATE_TIME 1
#endif

#endif // TORRENT_CONFIG_HPP_INCLUDED

<commit_msg>Include limits.h to get NAME_MAX on Unix.<commit_after>/*

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

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

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

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

*/

#ifndef TORRENT_CONFIG_HPP_INCLUDED
#define TORRENT_CONFIG_HPP_INCLUDED

#include <boost/config.hpp>
#include <boost/version.hpp>
#include <stdio.h> // for snprintf

#ifndef WIN32
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif

#ifndef PRId64
#ifdef _WIN32
#define PRId64 "I64d"
#else
#define PRId64 "lld"
#endif
#endif

#if defined(__GNUC__) && __GNUC__ >= 4

#define TORRENT_DEPRECATED __attribute__ ((deprecated))

# if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __attribute__ ((visibility("default")))
# else
#  define TORRENT_EXPORT
# endif

#elif defined(__GNUC__)

# define TORRENT_EXPORT

#elif defined(BOOST_MSVC)

#pragma warning(disable: 4258)
#pragma warning(disable: 4251)

# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# else
#  define TORRENT_EXPORT
# endif

#else
# define TORRENT_EXPORT
#endif

#ifndef TORRENT_DEPRECATED
#define TORRENT_DEPRECATED
#endif

// set up defines for target environments
#if (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \
	|| defined __FreeBSD_kernel__
#define TORRENT_BSD
#elif defined __linux__
#define TORRENT_LINUX
#elif defined WIN32
#define TORRENT_WINDOWS
#elif defined sun || defined __sun
#define TORRENT_SOLARIS
#else
#warning unkown OS, assuming BSD
#define TORRENT_BSD
#endif

#define TORRENT_USE_IPV6 1
#define TORRENT_USE_MLOCK 1
#define TORRENT_USE_READV 1
#define TORRENT_USE_WRITEV 1
#define TORRENT_USE_IOSTREAM 1

// should wpath or path be used?
#if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY \
	&& BOOST_VERSION >= 103400 && !defined __APPLE__
#define TORRENT_USE_WPATH 1
#else
#define TORRENT_USE_WPATH 0
#endif

#ifdef TORRENT_WINDOWS
#include <stdarg.h>
// this is the maximum number of characters in a
// path element / filename on windows
#define NAME_MAX 255
inline int snprintf(char* buf, int len, char const* fmt, ...)
{
	va_list lp;
	va_start(lp, fmt);
	return vsnprintf_s(buf, len, _TRUNCATE, fmt, lp);
}
#define strtoll _strtoi64
#else
#include <limits.h>
#endif

#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) && !defined (TORRENT_UPNP_LOGGING)
#define TORRENT_UPNP_LOGGING
#endif

#if !TORRENT_USE_WPATH && defined TORRENT_LINUX
// libiconv presnce, not implemented yet
#define TORRENT_USE_LOCALE_FILENAMES 1
#else
#define TORRENT_USE_LOCALE_FILENAMES 0
#endif

#if !defined(TORRENT_READ_HANDLER_MAX_SIZE)
# define TORRENT_READ_HANDLER_MAX_SIZE 256
#endif

#if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE)
# define TORRENT_WRITE_HANDLER_MAX_SIZE 256
#endif

// determine what timer implementation we can use

#if defined(__MACH__)
#define TORRENT_USE_ABSOLUTE_TIME 1
#elif defined(_WIN32)
#define TORRENT_USE_QUERY_PERFORMANCE_TIMER 1
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
#define TORRENT_USE_CLOCK_GETTIME 1
#else
#define TORRENT_USE_BOOST_DATE_TIME 1
#endif

#endif // TORRENT_CONFIG_HPP_INCLUDED

<|endoftext|>


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

//$Id: datasource.hpp 43 2005-04-22 18:52:47Z pavlenko $

#ifndef DATASOURCE_HPP
#define DATASOURCE_HPP
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/params.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature_layer_desc.hpp>
// boost
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
// stl
#include <map>
#include <string>

namespace mapnik {

typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

struct MAPNIK_DECL Featureset
{
    virtual feature_ptr next()=0;
    virtual ~Featureset() {};
};

typedef MAPNIK_DECL boost::shared_ptr<Featureset> featureset_ptr;

class MAPNIK_DECL datasource_exception : public std::exception
{
private:
    std::string message_;
public:
    datasource_exception(const std::string& message=std::string("no reason"))
        :message_(message) {}

    ~datasource_exception() throw() {}
    virtual const char* what() const throw()
    {
        return message_.c_str();
    }
};

class MAPNIK_DECL datasource : private boost::noncopyable
{
public:
    enum datasource_t {
        Vector,
        Raster
    };

    datasource (parameters const& params, bool bind=true)
        : params_(params),
          is_bound_(false)
        {}

    /*!
     * @brief Get the configuration parameters of the data source.
     *
     * These vary depending on the type of data source.
     *
     * @return The configuration parameters of the data source.
     */
    parameters const& params() const
    {
        return params_;
    }

    /*!
     * @brief Get the type of the datasource
     * @return The type of the datasource (Vector or Raster)
     */
    virtual int type() const=0;

    /*!
     * @brief Connect to the datasource
     */
    virtual void bind() const {};

    virtual featureset_ptr features(const query& q) const=0;
    virtual featureset_ptr features_at_point(coord2d const& pt) const=0;
    virtual box2d<double> envelope() const=0;
    virtual layer_descriptor get_descriptor() const=0;
    virtual ~datasource() {};
protected:
    parameters params_;
    mutable bool is_bound_;
};

typedef std::string datasource_name();
typedef datasource* create_ds(const parameters& params, bool bind);
typedef void destroy_ds(datasource *ds);

class datasource_deleter
{
public:
    void operator() (datasource* ds)
    {
        delete ds;
    }
};

typedef boost::shared_ptr<datasource> datasource_ptr;

#define DATASOURCE_PLUGIN(classname)                                    \
    extern "C" MAPNIK_EXP std::string datasource_name()                 \
    {                                                                   \
        return classname::name();                                       \
    }                                                                   \
    extern "C"  MAPNIK_EXP datasource* create(const parameters &params, bool bind) \
    {                                                                   \
        return new classname(params, bind);                             \
    }                                                                   \
    extern "C" MAPNIK_EXP void destroy(datasource *ds)                  \
    {                                                                   \
        delete ds;                                                      \
    }                                                                   \
    //
}

#endif //DATASOURCE_HPP
<commit_msg>+ remove 'bind' param   from datasource (base class) ctor   (FIXME: would be better to use parameters to           pass to specific options to concrete           datasource implementations)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: datasource.hpp 43 2005-04-22 18:52:47Z pavlenko $

#ifndef DATASOURCE_HPP
#define DATASOURCE_HPP
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/params.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature_layer_desc.hpp>
// boost
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
// stl
#include <map>
#include <string>

namespace mapnik {

typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

struct MAPNIK_DECL Featureset
{
    virtual feature_ptr next()=0;
    virtual ~Featureset() {};
};

typedef MAPNIK_DECL boost::shared_ptr<Featureset> featureset_ptr;

class MAPNIK_DECL datasource_exception : public std::exception
{
private:
    std::string message_;
public:
    datasource_exception(const std::string& message=std::string("no reason"))
        :message_(message) {}

    ~datasource_exception() throw() {}
    virtual const char* what() const throw()
    {
        return message_.c_str();
    }
};

class MAPNIK_DECL datasource : private boost::noncopyable
{
public:
    enum datasource_t {
        Vector,
        Raster
    };

    datasource (parameters const& params)
        : params_(params),
          is_bound_(false)
        {}

    /*!
     * @brief Get the configuration parameters of the data source.
     *
     * These vary depending on the type of data source.
     *
     * @return The configuration parameters of the data source.
     */
    parameters const& params() const
    {
        return params_;
    }

    /*!
     * @brief Get the type of the datasource
     * @return The type of the datasource (Vector or Raster)
     */
    virtual int type() const=0;

    /*!
     * @brief Connect to the datasource
     */
    virtual void bind() const {};

    virtual featureset_ptr features(const query& q) const=0;
    virtual featureset_ptr features_at_point(coord2d const& pt) const=0;
    virtual box2d<double> envelope() const=0;
    virtual layer_descriptor get_descriptor() const=0;
    virtual ~datasource() {};
protected:
    parameters params_;
    mutable bool is_bound_;
};

typedef std::string datasource_name();
typedef datasource* create_ds(const parameters& params, bool bind);
typedef void destroy_ds(datasource *ds);

class datasource_deleter
{
public:
    void operator() (datasource* ds)
    {
        delete ds;
    }
};

typedef boost::shared_ptr<datasource> datasource_ptr;

#define DATASOURCE_PLUGIN(classname)                                    \
    extern "C" MAPNIK_EXP std::string datasource_name()                 \
    {                                                                   \
        return classname::name();                                       \
    }                                                                   \
    extern "C"  MAPNIK_EXP datasource* create(const parameters &params, bool bind) \
    {                                                                   \
        return new classname(params, bind);                             \
    }                                                                   \
    extern "C" MAPNIK_EXP void destroy(datasource *ds)                  \
    {                                                                   \
        delete ds;                                                      \
    }                                                                   \
    //
}

#endif //DATASOURCE_HPP
<|endoftext|>


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

#ifndef MAPNIK_IMAGE_VIEW_HPP
#define MAPNIK_IMAGE_VIEW_HPP

namespace mapnik {

template <typename T>
class image_view
{
public:
    typedef typename T::pixel_type pixel_type;

    image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
        : x_(x),
          y_(y),
          width_(width),
          height_(height),
          data_(data)
    {
        if (x_ >= data_.width()) x_=data_.width()-1;
        if (y_ >= data_.height()) x_=data_.height()-1;
        if (x_ + width_ > data_.width()) width_= data_.width() - x_;
        if (y_ + height_ > data_.height()) height_= data_.height() - y_;
    }

    ~image_view() {}

    image_view(image_view<T> const& rhs)
        : x_(rhs.x_),
          y_(rhs.y_),
          width_(rhs.width_),
          height_(rhs.height_),
          data_(rhs.data_) {}

    image_view<T> & operator=(image_view<T> const& rhs)
    {
        if (&rhs==this) return *this;
        x_ = rhs.x_;
        y_ = rhs.y_;
        width_ = rhs.width_;
        height_ = rhs.height_;
        data_ = rhs.data_;
        return *this;
    }

    inline unsigned x() const
    {
        return x_;
    }

    inline unsigned y() const
    {
        return y_;
    }

    inline unsigned width() const
    {
        return width_;
    }

    inline unsigned height() const
    {
        return height_;
    }

    inline const pixel_type* getRow(unsigned row) const
    {
        return data_.getRow(row + y_) + x_;
    }
    inline T& data()
    {
        return data_;
    }
    inline T const& data() const
    {
        return data_;
    }

private:
    unsigned x_;
    unsigned y_;
    unsigned width_;
    unsigned height_;
    T const& data_;
};
}

#endif // MAPNIK_IMAGE_VIEW_HPP

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

#ifndef MAPNIK_IMAGE_VIEW_HPP
#define MAPNIK_IMAGE_VIEW_HPP

namespace mapnik {

template <typename T>
class image_view
{
public:
    typedef typename T::pixel_type pixel_type;

    image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
        : x_(x),
          y_(y),
          width_(width),
          height_(height),
          data_(data)
    {
        if (x_ >= data_.width()) x_=data_.width()-1;
        if (y_ >= data_.height()) x_=data_.height()-1;
        if (x_ + width_ > data_.width()) width_= data_.width() - x_;
        if (y_ + height_ > data_.height()) height_= data_.height() - y_;
    }

    ~image_view() {}

    image_view(image_view<T> const& rhs)
        : x_(rhs.x_),
          y_(rhs.y_),
          width_(rhs.width_),
          height_(rhs.height_),
          data_(rhs.data_) {}

    image_view<T> & operator=(image_view<T> const& rhs)
    {
        if (&rhs==this) return *this;
        x_ = rhs.x_;
        y_ = rhs.y_;
        width_ = rhs.width_;
        height_ = rhs.height_;
        data_ = rhs.data_;
        return *this;
    }

    inline unsigned x() const
    {
        return x_;
    }

    inline unsigned y() const
    {
        return y_;
    }

    inline unsigned width() const
    {
        return width_;
    }

    inline unsigned height() const
    {
        return height_;
    }

    inline const pixel_type* getRow(unsigned row) const
    {
        return data_.getRow(row + y_) + x_;
    }

    inline char const* getBytes() const
    {
        return reinterpret_cast<char const*>(&data_);
    }

    inline T& data()
    {
        return data_;
    }
    inline T const& data() const
    {
        return data_;
    }

private:
    unsigned x_;
    unsigned y_;
    unsigned width_;
    unsigned height_;
    T const& data_;
};
}

#endif // MAPNIK_IMAGE_VIEW_HPP
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius & Philippe Lhoste
 **/

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

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool isLuaOperator(char ch) {
	if (isalnum(ch))
		return false;
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
		ch == '(' || ch == ')' || ch == '=' ||
		ch == '{' || ch == '}' || ch == '~' ||
		ch == '[' || ch == ']' || ch == ';' ||
		ch == '<' || ch == '>' || ch == ',' ||
		ch == '.' || ch == '^' || ch == '%' || ch == ':')
		return true;
	return false;
}

static void ColouriseLuaDoc(
	unsigned int startPos,
	int length,
	int initStyle,
	WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];

	int currentLine = styler.GetLine(startPos);
	// Initialize the literal string [[ ... ]] nesting level, if we are inside such a string.
	int literalStringLevel = 0;
	if (initStyle == SCE_LUA_LITERALSTRING) {
		literalStringLevel = styler.GetLineState(currentLine - 1);
	}
	// Initialize the block comment --[[ ... ]] nesting level, if we are inside such a comment
	int blockCommentLevel = 0;
	if (initStyle == SCE_LUA_COMMENT) {
		blockCommentLevel = styler.GetLineState(currentLine - 1);
	}

	// Do not leak onto next line
	if (initStyle == SCE_LUA_STRINGEOL) {
		initStyle = SCE_LUA_DEFAULT;
	}

	StyleContext sc(startPos, length, initStyle, styler);
	if (startPos == 0 && sc.ch == '#') {
		// shbang line: # is a comment only if first char of the script
		sc.SetState(SCE_LUA_COMMENTLINE);
	}
	for (; sc.More(); sc.Forward()) {
		if (sc.atLineEnd) {
			// Update the line state, so it can be seen by next line
			currentLine = styler.GetLine(sc.currentPos);
			switch (sc.state) {
			case SCE_LUA_LITERALSTRING:
				// Inside a literal string, we set the line state
				styler.SetLineState(currentLine, literalStringLevel);
				break;
			case SCE_LUA_COMMENT: 	// Block comment
				// Inside a block comment, we set the line state
				styler.SetLineState(currentLine, blockCommentLevel);
				break;
			default:
				// Reset the line state
				styler.SetLineState(currentLine, 0);
				break;
			}
		}
		if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
			// Prevent SCE_LUA_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_LUA_STRING);
		}

		// Handle string line continuation
		if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) &&
		        sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_LUA_OPERATOR) {
			sc.SetState(SCE_LUA_DEFAULT);
		} else if (sc.state == SCE_LUA_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD2);
				} else if (keywords3.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD3);
				} else if (keywords4.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD4);
				} else if (keywords5.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD5);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				}
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_COMMENTLINE ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_PREPROCESSOR ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_CHARACTER) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_LITERALSTRING) {
			if (sc.Match('[', '[')) {
				literalStringLevel++;
				sc.Forward();
				sc.SetState(SCE_LUA_LITERALSTRING);
			} else if (sc.Match(']', ']') && literalStringLevel > 0) {
				literalStringLevel--;
				sc.Forward();
				if (literalStringLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		} else if (sc.state == SCE_LUA_COMMENT) {	// Lua 5.0's block comment
			if (sc.Match('[', '[')) {
				blockCommentLevel++;
				sc.Forward();
			} else if (sc.Match(']', ']') && blockCommentLevel > 0) {
				blockCommentLevel--;
				sc.Forward();
				if (blockCommentLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_LUA_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_LUA_NUMBER);
			} else if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_LUA_IDENTIFIER);
			} else if (sc.Match('\"')) {
				sc.SetState(SCE_LUA_STRING);
			} else if (sc.Match('\'')) {
				sc.SetState(SCE_LUA_CHARACTER);
			} else if (sc.Match('[', '[')) {
				literalStringLevel = 1;
				sc.SetState(SCE_LUA_LITERALSTRING);
				sc.Forward();
			} else if (sc.Match("--[[")) {	// Lua 5.0's block comment
				blockCommentLevel = 1;
				sc.SetState(SCE_LUA_COMMENT);
				sc.Forward(3);
			} else if (sc.Match('-', '-')) {
				sc.SetState(SCE_LUA_COMMENTLINE);
				sc.Forward();
			} else if (sc.atLineStart && sc.Match('$')) {
				sc.SetState(SCE_LUA_PREPROCESSOR);	// Obsolete since Lua 4.0, but still in old code
			} else if (isLuaOperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_LUA_OPERATOR);
			}
		}
	}
	sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];

	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j])) {
						break;
					}
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
					levelCurrent++;
				}
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
					levelCurrent--;
				}
			}
		} else if (style == SCE_LUA_OPERATOR) {
			if (ch == '{' || ch == '(') {
				levelCurrent++;
			} else if (ch == '}' || ch == ')') {
				levelCurrent--;
			}
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact) {
				lev |= SC_FOLDLEVELWHITEFLAG;
			}
			if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
				lev |= SC_FOLDLEVELHEADERFLAG;
			}
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch)) {
			visibleChars++;
		}
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const luaWordListDesc[] = {
	"Keywords",
	"Basic functions",
	"String & math functions",
	"I/O & system facilities",
	"XXX",
	"XXX",
	0
};

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, luaWordListDesc);
<commit_msg>Patch from Alexey to fold literal strings and comments.<commit_after>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius & Philippe Lhoste
 **/

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

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool isLuaOperator(char ch) {
	if (isalnum(ch))
		return false;
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
		ch == '(' || ch == ')' || ch == '=' ||
		ch == '{' || ch == '}' || ch == '~' ||
		ch == '[' || ch == ']' || ch == ';' ||
		ch == '<' || ch == '>' || ch == ',' ||
		ch == '.' || ch == '^' || ch == '%' || ch == ':')
		return true;
	return false;
}

static void ColouriseLuaDoc(
	unsigned int startPos,
	int length,
	int initStyle,
	WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];

	int currentLine = styler.GetLine(startPos);
	// Initialize the literal string [[ ... ]] nesting level, if we are inside such a string.
	int literalStringLevel = 0;
	if (initStyle == SCE_LUA_LITERALSTRING) {
		literalStringLevel = styler.GetLineState(currentLine - 1);
	}
	// Initialize the block comment --[[ ... ]] nesting level, if we are inside such a comment
	int blockCommentLevel = 0;
	if (initStyle == SCE_LUA_COMMENT) {
		blockCommentLevel = styler.GetLineState(currentLine - 1);
	}

	// Do not leak onto next line
	if (initStyle == SCE_LUA_STRINGEOL) {
		initStyle = SCE_LUA_DEFAULT;
	}

	StyleContext sc(startPos, length, initStyle, styler);
	if (startPos == 0 && sc.ch == '#') {
		// shbang line: # is a comment only if first char of the script
		sc.SetState(SCE_LUA_COMMENTLINE);
	}
	for (; sc.More(); sc.Forward()) {
		if (sc.atLineEnd) {
			// Update the line state, so it can be seen by next line
			currentLine = styler.GetLine(sc.currentPos);
			switch (sc.state) {
			case SCE_LUA_LITERALSTRING:
				// Inside a literal string, we set the line state
				styler.SetLineState(currentLine, literalStringLevel);
				break;
			case SCE_LUA_COMMENT: 	// Block comment
				// Inside a block comment, we set the line state
				styler.SetLineState(currentLine, blockCommentLevel);
				break;
			default:
				// Reset the line state
				styler.SetLineState(currentLine, 0);
				break;
			}
		}
		if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
			// Prevent SCE_LUA_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_LUA_STRING);
		}

		// Handle string line continuation
		if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) &&
		        sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_LUA_OPERATOR) {
			sc.SetState(SCE_LUA_DEFAULT);
		} else if (sc.state == SCE_LUA_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD2);
				} else if (keywords3.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD3);
				} else if (keywords4.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD4);
				} else if (keywords5.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD5);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				}
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_COMMENTLINE ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_PREPROCESSOR ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_CHARACTER) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_LITERALSTRING) {
			if (sc.Match('[', '[')) {
				literalStringLevel++;
				sc.Forward();
				sc.SetState(SCE_LUA_LITERALSTRING);
			} else if (sc.Match(']', ']') && literalStringLevel > 0) {
				literalStringLevel--;
				sc.Forward();
				if (literalStringLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		} else if (sc.state == SCE_LUA_COMMENT) {	// Lua 5.0's block comment
			if (sc.Match('[', '[')) {
				blockCommentLevel++;
				sc.Forward();
			} else if (sc.Match(']', ']') && blockCommentLevel > 0) {
				blockCommentLevel--;
				sc.Forward();
				if (blockCommentLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_LUA_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_LUA_NUMBER);
			} else if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_LUA_IDENTIFIER);
			} else if (sc.Match('\"')) {
				sc.SetState(SCE_LUA_STRING);
			} else if (sc.Match('\'')) {
				sc.SetState(SCE_LUA_CHARACTER);
			} else if (sc.Match('[', '[')) {
				literalStringLevel = 1;
				sc.SetState(SCE_LUA_LITERALSTRING);
				sc.Forward();
			} else if (sc.Match("--[[")) {	// Lua 5.0's block comment
				blockCommentLevel = 1;
				sc.SetState(SCE_LUA_COMMENT);
				sc.Forward(3);
			} else if (sc.Match('-', '-')) {
				sc.SetState(SCE_LUA_COMMENTLINE);
				sc.Forward();
			} else if (sc.atLineStart && sc.Match('$')) {
				sc.SetState(SCE_LUA_PREPROCESSOR);	// Obsolete since Lua 4.0, but still in old code
			} else if (isLuaOperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_LUA_OPERATOR);
			}
		}
	}
	sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];

	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j])) {
						break;
					}
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
					levelCurrent++;
				}
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
					levelCurrent--;
				}
			}
		} else if (style == SCE_LUA_OPERATOR) {
			if (ch == '{' || ch == '(') {
				levelCurrent++;
			} else if (ch == '}' || ch == ')') {
				levelCurrent--;
			}
		} else if (style == SCE_LUA_COMMENT || style == SCE_LUA_LITERALSTRING) {
			if (ch == '[' && chNext == '[') {
				levelCurrent++;
			} else if (ch == ']' && chNext == ']') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact) {
				lev |= SC_FOLDLEVELWHITEFLAG;
			}
			if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
				lev |= SC_FOLDLEVELHEADERFLAG;
			}
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch)) {
			visibleChars++;
		}
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const luaWordListDesc[] = {
	"Keywords",
	"Basic functions",
	"String & math functions",
	"I/O & system facilities",
	"XXX",
	"XXX",
	0
};

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, luaWordListDesc);
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius & Philippe Lhoste
 **/

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

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

#define SCE_LUA_LAST_STYLE	SCE_LUA_WORD6

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool isLuaOperator(char ch) {
	if (isalnum(ch))
		return false;
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
		ch == '(' || ch == ')' || ch == '=' ||
		ch == '{' || ch == '}' || ch == '~' ||
		ch == '[' || ch == ']' || ch == ';' ||
		ch == '<' || ch == '>' || ch == ',' ||
		ch == '.' || ch == '^' || ch == '%' || ch == ':')
		return true;
	return false;
}

static void ColouriseLuaDoc(
	unsigned int startPos,
	int length,
	int initStyle,
	WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];

	// Must initialize the literal string nesting level, if we are inside such a string.
	int literalStringLevel = 0;
	if (initStyle == SCE_LUA_LITERALSTRING) {
		literalStringLevel = 1;
	}
	// We use states above the last one to indicate nesting level of literal strings
	if (initStyle > SCE_LUA_LAST_STYLE) {
		literalStringLevel = initStyle - SCE_LUA_LAST_STYLE + 1;
	}

	// Do not leak onto next line
	if (initStyle == SCE_LUA_STRINGEOL) {
		initStyle = SCE_LUA_DEFAULT;
	}

	StyleContext sc(startPos, length, initStyle, styler);
	if (startPos == 0 && sc.ch == '#') {
		sc.SetState(SCE_LUA_COMMENTLINE);
	}
	for (; sc.More(); sc.Forward()) {
		if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
			// Prevent SCE_LUA_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_LUA_STRING);
		}

		// Handle string line continuation
		if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) &&
				sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_LUA_OPERATOR) {
			sc.SetState(SCE_LUA_DEFAULT);
		} else if (sc.state == SCE_LUA_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD2);
				} else if (keywords3.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD3);
				} else if (keywords4.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD4);
				} else if (keywords5.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD5);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				}
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_COMMENTLINE ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_PREPROCESSOR ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_CHARACTER) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_LITERALSTRING || sc.state > SCE_LUA_LAST_STYLE) {
			if (sc.Match('[', '[')) {
				literalStringLevel++;
				sc.SetState(SCE_LUA_LAST_STYLE + literalStringLevel - 1);
			} else if (sc.Match(']', ']') && literalStringLevel > 0) {
				literalStringLevel--;
				sc.Forward();
				if (literalStringLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				} else if (literalStringLevel == 1) {
					sc.ForwardSetState(SCE_LUA_LITERALSTRING);
				} else {
					sc.ForwardSetState(SCE_LUA_LAST_STYLE + literalStringLevel - 1);
				}
			}
		}
		// Determine if a new state should be entered.
		if (sc.state == SCE_LUA_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_LUA_NUMBER);
			} else if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_LUA_IDENTIFIER);
			} else if (sc.Match('\"')) {
				sc.SetState(SCE_LUA_STRING);
			} else if (sc.Match('\'')) {
				sc.SetState(SCE_LUA_CHARACTER);
			} else if (sc.Match('[', '[')) {
				literalStringLevel = 1;
				sc.SetState(SCE_LUA_LITERALSTRING);
				sc.Forward();
			} else if (sc.Match('-', '-')) {
				sc.SetState(SCE_LUA_COMMENTLINE);
				sc.Forward();
			} else if (sc.Match('$') && sc.atLineStart) {
				sc.SetState(SCE_LUA_PREPROCESSOR);	// Obsolete since Lua 4.0, but still in old code
			}  else if (isLuaOperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_LUA_OPERATOR);
			}
		}
	}
	sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];

	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j])) {
						break;
					}
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
					levelCurrent++;
				}
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
					levelCurrent--;
				}
			}
		} else if (style == SCE_LUA_OPERATOR) {
			if (ch == '{' || ch == '(') {
				levelCurrent++;
			} else if (ch == '}' || ch == ')') {
				levelCurrent--;
			}
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact) {
				lev |= SC_FOLDLEVELWHITEFLAG;
			}
			if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
				lev |= SC_FOLDLEVELHEADERFLAG;
			}
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch)) {
			visibleChars++;
		}
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc);
<commit_msg>Patch from Philippe to handle block comments, and the deep nesting of strings and block comments.<commit_after>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius & Philippe Lhoste
 **/

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

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool isLuaOperator(char ch) {
	if (isalnum(ch))
		return false;
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
		ch == '(' || ch == ')' || ch == '=' ||
		ch == '{' || ch == '}' || ch == '~' ||
		ch == '[' || ch == ']' || ch == ';' ||
		ch == '<' || ch == '>' || ch == ',' ||
		ch == '.' || ch == '^' || ch == '%' || ch == ':')
		return true;
	return false;
}

static void ColouriseLuaDoc(
	unsigned int startPos,
	int length,
	int initStyle,
	WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];

	int currentLine = styler.GetLine(startPos);
	// Initialize the literal string [[ ... ]] nesting level, if we are inside such a string.
	int literalStringLevel = 0;
	if (initStyle == SCE_LUA_LITERALSTRING) {
		literalStringLevel = styler.GetLineState(currentLine - 1);
	}
	// Initialize the block comment --[[ ... ]] nesting level, if we are inside such a comment
	int blockCommentLevel = 0;
	if (initStyle == SCE_LUA_COMMENT) {
		blockCommentLevel = styler.GetLineState(currentLine - 1);
	}

	// Do not leak onto next line
	if (initStyle == SCE_LUA_STRINGEOL) {
		initStyle = SCE_LUA_DEFAULT;
	}

	StyleContext sc(startPos, length, initStyle, styler);
	if (startPos == 0 && sc.ch == '#') {
		// shbang line: # is a comment only if first char of the script
		sc.SetState(SCE_LUA_COMMENTLINE);
	}
	for (; sc.More(); sc.Forward()) {
		if (sc.atLineEnd) {
			// Update the line state, so it can be seen by next line
			currentLine = styler.GetLine(sc.currentPos);
			switch (sc.state) {
			case SCE_LUA_LITERALSTRING:
				// Inside a literal string, we set the line state
				styler.SetLineState(currentLine, literalStringLevel);
				break;
			case SCE_LUA_COMMENT: 	// Block comment
				// Inside a block comment, we set the line state
				styler.SetLineState(currentLine, blockCommentLevel);
				break;
			default:
				// Reset the line state
				styler.SetLineState(currentLine, 0);
				break;
			}
		}
		if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
			// Prevent SCE_LUA_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_LUA_STRING);
		}

		// Handle string line continuation
		if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) &&
		        sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_LUA_OPERATOR) {
			sc.SetState(SCE_LUA_DEFAULT);
		} else if (sc.state == SCE_LUA_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD2);
				} else if (keywords3.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD3);
				} else if (keywords4.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD4);
				} else if (keywords5.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD5);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				}
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_COMMENTLINE ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_PREPROCESSOR ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_CHARACTER) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_LITERALSTRING) {
			if (sc.Match('[', '[')) {
				literalStringLevel++;
				sc.Forward();
				sc.SetState(SCE_LUA_LITERALSTRING);
			} else if (sc.Match(']', ']') && literalStringLevel > 0) {
				literalStringLevel--;
				sc.Forward();
				if (literalStringLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		} else if (sc.state == SCE_LUA_COMMENT) {	// Lua 5.0's block comment
			if (sc.Match('[', '[')) {
				blockCommentLevel++;
				sc.Forward();
			} else if (sc.Match(']', ']') && blockCommentLevel > 0) {
				blockCommentLevel--;
				sc.Forward();
				if (blockCommentLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_LUA_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_LUA_NUMBER);
			} else if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_LUA_IDENTIFIER);
			} else if (sc.Match('\"')) {
				sc.SetState(SCE_LUA_STRING);
			} else if (sc.Match('\'')) {
				sc.SetState(SCE_LUA_CHARACTER);
			} else if (sc.Match('[', '[')) {
				literalStringLevel = 1;
				sc.SetState(SCE_LUA_LITERALSTRING);
				sc.Forward();
			} else if (sc.Match("--[[")) {	// Lua 5.0's block comment
				blockCommentLevel = 1;
				sc.SetState(SCE_LUA_COMMENT);
				sc.Forward(3);
			} else if (sc.Match('-', '-')) {
				sc.SetState(SCE_LUA_COMMENTLINE);
				sc.Forward();
			} else if (sc.atLineStart && sc.Match('$')) {
				sc.SetState(SCE_LUA_PREPROCESSOR);	// Obsolete since Lua 4.0, but still in old code
			} else if (isLuaOperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_LUA_OPERATOR);
			}
		}
	}
	sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];

	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j])) {
						break;
					}
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
					levelCurrent++;
				}
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
					levelCurrent--;
				}
			}
		} else if (style == SCE_LUA_OPERATOR) {
			if (ch == '{' || ch == '(') {
				levelCurrent++;
			} else if (ch == '}' || ch == ')') {
				levelCurrent--;
			}
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact) {
				lev |= SC_FOLDLEVELWHITEFLAG;
			}
			if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
				lev |= SC_FOLDLEVELHEADERFLAG;
			}
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch)) {
			visibleChars++;
		}
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc);
<|endoftext|>


<commit_before>#include "Logger.h"
#include <ctime>

#include <QTextStream>

DEFINE_SINGLETON_SCOPE( Logger );

Logger::Logger()
  : mFile( NULL ), mProcessMessages( false )
{
}

Logger::~Logger() {
  if( mFile ) {
    delete mFile;
    mFile = NULL;
  }
}

void Logger::StartProcessing() {
  mProcessMessages = true;
  ProcessMessages();
}

void Logger::SetLogPath( const QString& path ) {
  if( mFile )
    delete mFile;

  mFile = new QFile( path );
  if( mFile )  {
    mFile->open( QIODevice::WriteOnly | QIODevice::Text );
  }
}

void Logger::ProcessMessages() {
  if( !mProcessMessages )
    return;

  for( auto it : mQueue ) {
    LogEventType type = it.first;
    const QString& msg = it.second;

    if( mFile && mFile->isOpen() ) {
      QTextStream out( mFile );
      out << msg;
      mFile->flush();
    }

    emit NewMessage( type, msg );
  }
}

void Logger::Add( LogEventType type, const char *fmt, ... ) {
  char buffer[ 4096 ];

  // Parse vargs
  va_list args;
  va_start( args, fmt );
  vsnprintf( buffer, sizeof(buffer), fmt, args );
  va_end( args );

  // Timestamp
  char timestamp[ 256 ];
  time_t t = time( 0 );
  struct tm *now = localtime( &t );
  strftime( timestamp, sizeof( timestamp ), "%H:%M:%S", now );

  // Decorate
  char decorated[ 4096 ];
  sprintf( decorated, "[%s] %s: %s\n", timestamp, LOG_EVENT_TYPE_NAMES[ type ], buffer );
  QString line( decorated );

  mQueue.push_back( QPair< LogEventType, QString >( type, line ) );
  ProcessMessages();
}
<commit_msg>Clear log messages upon processing<commit_after>#include "Logger.h"
#include <ctime>

#include <QTextStream>

DEFINE_SINGLETON_SCOPE( Logger );

Logger::Logger()
  : mFile( NULL ), mProcessMessages( false )
{
}

Logger::~Logger() {
  if( mFile ) {
    delete mFile;
    mFile = NULL;
  }
}

void Logger::StartProcessing() {
  mProcessMessages = true;
  ProcessMessages();
}

void Logger::SetLogPath( const QString& path ) {
  if( mFile )
    delete mFile;

  mFile = new QFile( path );
  if( mFile )  {
    mFile->open( QIODevice::WriteOnly | QIODevice::Text );
  }
}

void Logger::ProcessMessages() {
  if( !mProcessMessages )
    return;

  for( auto it : mQueue ) {
    LogEventType type = it.first;
    const QString& msg = it.second;

    if( mFile && mFile->isOpen() ) {
      QTextStream out( mFile );
      out << msg;
      mFile->flush();
    }

    emit NewMessage( type, msg );
  }

  mQueue.clear();
}

void Logger::Add( LogEventType type, const char *fmt, ... ) {
  char buffer[ 4096 ];

  // Parse vargs
  va_list args;
  va_start( args, fmt );
  vsnprintf( buffer, sizeof(buffer), fmt, args );
  va_end( args );

  // Timestamp
  char timestamp[ 256 ];
  time_t t = time( 0 );
  struct tm *now = localtime( &t );
  strftime( timestamp, sizeof( timestamp ), "%H:%M:%S", now );

  // Decorate
  char decorated[ 4096 ];
  sprintf( decorated, "[%s] %s: %s\n", timestamp, LOG_EVENT_TYPE_NAMES[ type ], buffer );
  QString line( decorated );

  mQueue.push_back( QPair< LogEventType, QString >( type, line ) );
  ProcessMessages();
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

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

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

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

#pragma once

#include <cstdint>
#include <string>
#include <type_traits>

namespace raz
{
	class SerializationError : public std::exception
	{
	public:
		virtual const char* what() const
		{
			return "Serialization error";
		}
	};

	enum SerializationMode
	{
		SERIALIZE,
		DESERIALIZE
	};

	template<class BufferType, bool EndiannessConversion = false>
	class Serializer : public BufferType
	{
	public:
		template<class... Args>
		Serializer(Args... args) : BufferType(std::forward<Args>(args)...)
		{
		}

		template<class I>
		typename std::enable_if_t<std::is_integral<I>::value, Serializer>&
			operator()(I& i)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				I tmp = i;

				if (sizeof(I) > 1 && EndiannessConversion && !isBigEndian())
					tmp = swapEndianness(tmp);

				if (BufferType::write(reinterpret_cast<const char*>(&tmp), sizeof(I)) < sizeof(I))
					throw SerializationError();
			}
			else
			{
				I tmp;

				if (BufferType::read(reinterpret_cast<char*>(&tmp), sizeof(I)) < sizeof(I))
					throw SerializationError();

				if (sizeof(I) > 1 && EndiannessConversion && !isBigEndian())
					tmp = swapEndianness(tmp);

				i = tmp;
			}

			return *this;
		}

		Serializer& operator()(float& f)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				uint32_t tmp = static_cast<uint32_t>(pack754(f, 32, 8));
				(*this)(tmp);
			}
			else
			{
				uint32_t tmp;
				(*this)(tmp);
				f = static_cast<float>(unpack754(tmp, 32, 8));
			}

			return *this;
		}

		Serializer& operator()(double& d)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				uint64_t tmp = pack754(d, 64, 11);
				(*this)(tmp);
			}
			else
			{
				uint64_t tmp;
				(*this)(tmp);
				d = static_cast<double>(unpack754(tmp, 64, 11));
			}

			return *this;
		}

		template<class Allocator>
		Serializer& operator()(std::basic_string<char, std::char_traits<char>, Allocator>& str)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				uint32_t len = static_cast<uint32_t>(str.length());
				(*this)(len);

				if (BufferType::write(str.c_str(), len) < len)
					throw SerializationError();
			}
			else
			{
				uint32_t len;
				(*this)(len);

				str.resize(len);
				if (BufferType::read(&str[0], len) < len)
					throw SerializationError();
			}

			return *this;
		}

		template<class T>
		typename std::enable_if_t<!std::is_arithmetic<T>::value, Serializer>& operator()(T& t)
		{
			t(*this);
			return *this;
		}

	private:
		static constexpr bool isBigEndian()
		{
			union
			{
				uint32_t i;
				char c[4];
			} chk = { 0x01020304 };

			return (chk.c[0] == 1);
		}

		template<class T>
		static T swapEndianness(T t)
		{
			union
			{
				T t;
				unsigned char t8[sizeof(T)];
			} source, dest;

			source.t = t;

			for (size_t i = 0; i < sizeof(T); i++)
				dest.t8[i] = source.t8[sizeof(T) - i - 1];

			return dest.t;
		}

#pragma warning(push)
#pragma warning(disable: 4244) // possible loss of data

		/*
		Original public domain code:
		http://beej.us/guide/bgnet/examples/ieee754.c
		*/

		static uint64_t pack754(long double f, unsigned bits, unsigned expbits)
		{
			long double fnorm;
			int shift;
			long long sign, exp, significand;
			unsigned significandbits = bits - expbits - 1; // -1 for sign bit

			if (f == 0.0) return 0; // get this special case out of the way

									// check sign and begin normalization
			if (f < 0) { sign = 1; fnorm = -f; }
			else { sign = 0; fnorm = f; }

			// get the normalized form of f and track the exponent
			shift = 0;
			while (fnorm >= 2.0) { fnorm /= 2.0; shift++; }
			while (fnorm < 1.0) { fnorm *= 2.0; shift--; }
			fnorm = fnorm - 1.0;

			// calculate the binary form (non-float) of the significand data
			significand = fnorm * ((1LL << significandbits) + 0.5f);

			// get the biased exponent
			exp = shift + ((1 << (expbits - 1)) - 1); // shift + bias

													  // return the final answer
			return (sign << (bits - 1)) | (exp << (bits - expbits - 1)) | significand;
		}

		static long double unpack754(uint64_t i, unsigned bits, unsigned expbits)
		{
			long double result;
			long long shift;
			unsigned bias;
			unsigned significandbits = bits - expbits - 1; // -1 for sign bit

			if (i == 0) return 0.0;

			// pull the significand
			result = (i&((1LL << significandbits) - 1)); // mask
			result /= (1LL << significandbits); // convert back to float
			result += 1.0f; // add the one back on

							// deal with the exponent
			bias = (1 << (expbits - 1)) - 1;
			shift = ((i >> significandbits)&((1LL << expbits) - 1)) - bias;
			while (shift > 0) { result *= 2.0; shift--; }
			while (shift < 0) { result /= 2.0; shift++; }

			// sign it
			result *= (i >> (bits - 1)) & 1 ? -1.0 : 1.0;

			return result;
		}

#pragma warning(pop)

	};

	template<class T>
	class IsSerializer
	{
		template<class U, bool E>
		static std::true_type test(Serializer<U, E> const &);

		static std::false_type test(...);

	public:
		static bool const value = decltype(test(std::declval<T>()))::value;
	};

	template<class Serializer, class T = void>
	using EnableSerializer = std::enable_if_t<IsSerializer<Serializer>::value, T>;
}
<commit_msg>Added std::array and std::vector compatibility to Serializer<commit_after>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

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

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

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

#pragma once

#include <array>
#include <cstdint>
#include <string>
#include <vector>
#include <type_traits>

namespace raz
{
	class SerializationError : public std::exception
	{
	public:
		virtual const char* what() const
		{
			return "Serialization error";
		}
	};

	enum SerializationMode
	{
		SERIALIZE,
		DESERIALIZE
	};

	template<class BufferType, bool EndiannessConversion = false>
	class Serializer : public BufferType
	{
	public:
		template<class... Args>
		Serializer(Args... args) : BufferType(std::forward<Args>(args)...)
		{
		}

		template<class I>
		typename std::enable_if_t<std::is_integral<I>::value, Serializer>&
			operator()(I& i)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				I tmp = i;

				if (sizeof(I) > 1 && EndiannessConversion && !isBigEndian())
					tmp = swapEndianness(tmp);

				if (BufferType::write(reinterpret_cast<const char*>(&tmp), sizeof(I)) < sizeof(I))
					throw SerializationError();
			}
			else
			{
				I tmp;

				if (BufferType::read(reinterpret_cast<char*>(&tmp), sizeof(I)) < sizeof(I))
					throw SerializationError();

				if (sizeof(I) > 1 && EndiannessConversion && !isBigEndian())
					tmp = swapEndianness(tmp);

				i = tmp;
			}

			return *this;
		}

		Serializer& operator()(float& f)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				uint32_t tmp = static_cast<uint32_t>(pack754(f, 32, 8));
				(*this)(tmp);
			}
			else
			{
				uint32_t tmp;
				(*this)(tmp);
				f = static_cast<float>(unpack754(tmp, 32, 8));
			}

			return *this;
		}

		Serializer& operator()(double& d)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				uint64_t tmp = pack754(d, 64, 11);
				(*this)(tmp);
			}
			else
			{
				uint64_t tmp;
				(*this)(tmp);
				d = static_cast<double>(unpack754(tmp, 64, 11));
			}

			return *this;
		}

		template<class T, size_t N>
		Serializer& operator()(std::array<T, N>& arr)
		{
			for (auto& t : arr)
				(*this)(t);
		}

		template<class Allocator>
		Serializer& operator()(std::basic_string<char, std::char_traits<char>, Allocator>& str)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				uint32_t len = static_cast<uint32_t>(str.length());
				(*this)(len);

				if (BufferType::write(str.c_str(), len) < len)
					throw SerializationError();
			}
			else
			{
				uint32_t len;
				(*this)(len);

				str.resize(len);

				if (BufferType::read(&str[0], len) < len)
					throw SerializationError();
			}

			return *this;
		}

		template<class T, class Allocator>
		Serializer& operator()(std::vector<T, Allocator>& vec)
		{
			if (BufferType::getMode() == SerializationMode::SERIALIZE)
			{
				uint32_t len = static_cast<uint32_t>(vec.size());
				(*this)(len);

				for (auto& t : vec)
					(*this)(t);
			}
			else
			{
				uint32_t len;
				(*this)(len);

				vec.resize(vec.size() + len);

				for (auto& t : vec)
					(*this)(t);
			}

			return *this;
		}

		template<class T>
		typename std::enable_if_t<!std::is_arithmetic<T>::value, Serializer>& operator()(T& t)
		{
			t(*this);
			return *this;
		}

	private:
		static constexpr bool isBigEndian()
		{
			union
			{
				uint32_t i;
				char c[4];
			} chk = { 0x01020304 };

			return (chk.c[0] == 1);
		}

		template<class T>
		static T swapEndianness(T t)
		{
			union
			{
				T t;
				unsigned char t8[sizeof(T)];
			} source, dest;

			source.t = t;

			for (size_t i = 0; i < sizeof(T); i++)
				dest.t8[i] = source.t8[sizeof(T) - i - 1];

			return dest.t;
		}

#pragma warning(push)
#pragma warning(disable: 4244) // possible loss of data

		/*
		Original public domain code:
		http://beej.us/guide/bgnet/examples/ieee754.c
		*/

		static uint64_t pack754(long double f, unsigned bits, unsigned expbits)
		{
			long double fnorm;
			int shift;
			long long sign, exp, significand;
			unsigned significandbits = bits - expbits - 1; // -1 for sign bit

			if (f == 0.0) return 0; // get this special case out of the way

									// check sign and begin normalization
			if (f < 0) { sign = 1; fnorm = -f; }
			else { sign = 0; fnorm = f; }

			// get the normalized form of f and track the exponent
			shift = 0;
			while (fnorm >= 2.0) { fnorm /= 2.0; shift++; }
			while (fnorm < 1.0) { fnorm *= 2.0; shift--; }
			fnorm = fnorm - 1.0;

			// calculate the binary form (non-float) of the significand data
			significand = fnorm * ((1LL << significandbits) + 0.5f);

			// get the biased exponent
			exp = shift + ((1 << (expbits - 1)) - 1); // shift + bias

													  // return the final answer
			return (sign << (bits - 1)) | (exp << (bits - expbits - 1)) | significand;
		}

		static long double unpack754(uint64_t i, unsigned bits, unsigned expbits)
		{
			long double result;
			long long shift;
			unsigned bias;
			unsigned significandbits = bits - expbits - 1; // -1 for sign bit

			if (i == 0) return 0.0;

			// pull the significand
			result = (i&((1LL << significandbits) - 1)); // mask
			result /= (1LL << significandbits); // convert back to float
			result += 1.0f; // add the one back on

							// deal with the exponent
			bias = (1 << (expbits - 1)) - 1;
			shift = ((i >> significandbits)&((1LL << expbits) - 1)) - bias;
			while (shift > 0) { result *= 2.0; shift--; }
			while (shift < 0) { result /= 2.0; shift++; }

			// sign it
			result *= (i >> (bits - 1)) & 1 ? -1.0 : 1.0;

			return result;
		}

#pragma warning(pop)

	};

	template<class T>
	class IsSerializer
	{
		template<class U, bool E>
		static std::true_type test(Serializer<U, E> const &);

		static std::false_type test(...);

	public:
		static bool const value = decltype(test(std::declval<T>()))::value;
	};

	template<class Serializer, class T = void>
	using EnableSerializer = std::enable_if_t<IsSerializer<Serializer>::value, T>;
}
<|endoftext|>