<commit_before>/*

Copyright (c) 2008, 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_ALLOCA

#include "libtorrent/config.hpp"

#ifdef TORRENT_WINDOWS

#include <malloc.h>
#define TORRENT_ALLOCA(t, n) static_cast<t*>(_alloca(sizeof(t) * (n)))

#else

#include <alloca.h>

#define TORRENT_ALLOCA(t, n) static_cast<t*>(alloca(sizeof(t) * (n)))

#endif

#endif

<commit_msg>another FreeBSD fix<commit_after>/*

Copyright (c) 2008, 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_ALLOCA

#include "libtorrent/config.hpp"

#if defined TORRENT_WINDOWS

#include <malloc.h>
#define TORRENT_ALLOCA(t, n) static_cast<t*>(_alloca(sizeof(t) * (n)))

#elif defined TORRENT_BSD

#include <stdlib.h>
#define TORRENT_ALLOCA(t, n) static_cast<t*>(alloca(sizeof(t) * (n)))

#else

#include <alloca.h>
#define TORRENT_ALLOCA(t, n) static_cast<t*>(alloca(sizeof(t) * (n)))

#endif

#endif

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Nils Asmussen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 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.
 *
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the FreeBSD Project.
 */

#ifndef __ARCH_M3_X86_SYSTEM_HH__
#define __ARCH_M3_X86_SYSTEM_HH__

#include <string>
#include <vector>

#include "arch/x86/system.hh"
#include "params/M3X86System.hh"
#include "mem/qport.hh"
#include "mem/dtu/noc_addr.hh"
#include "sim/dtu_memory.hh"

class M3X86System : public X86System, public DTUMemory
{
  protected:
    static const size_t MAX_MODS        = 64;
    static const size_t MAX_PES         = 64;
    static const size_t RT_SIZE         = 0x2000;
    static const uintptr_t RT_START     = 0x3000;
    static const size_t STACK_SIZE      = 0x1000;
    static const uintptr_t STACK_AREA   = RT_START + RT_SIZE;
    static const size_t HEAP_SIZE       = 0x1000;
    static const unsigned RES_PAGES;

    class NoCMasterPort : public QueuedMasterPort
    {
      protected:

        ReqPacketQueue reqQueue;

        SnoopRespPacketQueue snoopRespQueue;

      public:

        NoCMasterPort(M3X86System &_sys);

        bool recvTimingResp(PacketPtr) override
        {
            // unused
            return true;
        }
    };

    struct BootModule
    {
        char name[128];
        uint64_t addr;
        uint64_t size;
    } M5_ATTR_PACKED;

    struct KernelEnv
    {
        enum
        {
            TYPE_IMEM    = 0,
            TYPE_EMEM    = 1,
            TYPE_MEM     = 2,
        };

        uint64_t mods[MAX_MODS];
        uint64_t pe_count;
        uint32_t pes[MAX_PES];
    } M5_ATTR_PACKED;

    struct StartEnv
    {
        uint64_t coreid;
        uint32_t argc;
        char **argv;

        uint64_t sp;
        uint64_t entry;
        uint64_t lambda;
        uint32_t pager_sess;
        uint32_t pager_gate;
        uint32_t mounts_len;
        uint64_t mounts;
        uint32_t fds_len;
        uint64_t fds;
        uint64_t eps;
        uint64_t caps;
        uint64_t exit;
        uint64_t heapsize;

        uint64_t backend;
        uint64_t kenv;
        uint32_t pe;
    } M5_ATTR_PACKED;

    NoCMasterPort nocPort;
    std::vector<Addr> pes;
    std::string commandLine;

  public:
    const unsigned coreId;
    const Addr modOffset;
    const Addr modSize;

  public:
    typedef M3X86SystemParams Params;
    M3X86System(Params *p);
    ~M3X86System();

    BaseMasterPort& getMasterPort(const std::string &if_name,
                                  PortID idx = InvalidPortID) override;

    void initState();

  private:
    bool isKernelArg(const std::string &arg);
    void mapMemory();
    size_t getArgc() const;
    void writeRemote(Addr dest, const uint8_t *data, size_t size);
    void writeArg(Addr &args, size_t &i, Addr argv, const char *cmd, const char *begin);
    Addr loadModule(const std::string &path, const std::string &name, Addr addr);
};

#endif
<commit_msg>M3System: added isr64_handler to StartEnv.<commit_after>/*
 * Copyright (c) 2015, Nils Asmussen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 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.
 *
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the FreeBSD Project.
 */

#ifndef __ARCH_M3_X86_SYSTEM_HH__
#define __ARCH_M3_X86_SYSTEM_HH__

#include <string>
#include <vector>

#include "arch/x86/system.hh"
#include "params/M3X86System.hh"
#include "mem/qport.hh"
#include "mem/dtu/noc_addr.hh"
#include "sim/dtu_memory.hh"

class M3X86System : public X86System, public DTUMemory
{
  protected:
    static const size_t MAX_MODS        = 64;
    static const size_t MAX_PES         = 64;
    static const size_t RT_SIZE         = 0x2000;
    static const uintptr_t RT_START     = 0x3000;
    static const size_t STACK_SIZE      = 0x1000;
    static const uintptr_t STACK_AREA   = RT_START + RT_SIZE;
    static const size_t HEAP_SIZE       = 0x1000;
    static const unsigned RES_PAGES;

    class NoCMasterPort : public QueuedMasterPort
    {
      protected:

        ReqPacketQueue reqQueue;

        SnoopRespPacketQueue snoopRespQueue;

      public:

        NoCMasterPort(M3X86System &_sys);

        bool recvTimingResp(PacketPtr) override
        {
            // unused
            return true;
        }
    };

    struct BootModule
    {
        char name[128];
        uint64_t addr;
        uint64_t size;
    } M5_ATTR_PACKED;

    struct KernelEnv
    {
        enum
        {
            TYPE_IMEM    = 0,
            TYPE_EMEM    = 1,
            TYPE_MEM     = 2,
        };

        uint64_t mods[MAX_MODS];
        uint64_t pe_count;
        uint32_t pes[MAX_PES];
    } M5_ATTR_PACKED;

    struct StartEnv
    {
        uint64_t coreid;
        uint32_t argc;
        char **argv;

        uint64_t sp;
        uint64_t entry;
        uint64_t lambda;
        uint32_t pager_sess;
        uint32_t pager_gate;
        uint32_t mounts_len;
        uint64_t mounts;
        uint32_t fds_len;
        uint64_t fds;
        uint64_t eps;
        uint64_t caps;
        uint64_t exit;
        uint64_t heapsize;

        uint64_t backend;
        uint64_t kenv;
        uint32_t pe;

        uint64_t isr64_handler;
    } M5_ATTR_PACKED;

    NoCMasterPort nocPort;
    std::vector<Addr> pes;
    std::string commandLine;

  public:
    const unsigned coreId;
    const Addr modOffset;
    const Addr modSize;

  public:
    typedef M3X86SystemParams Params;
    M3X86System(Params *p);
    ~M3X86System();

    BaseMasterPort& getMasterPort(const std::string &if_name,
                                  PortID idx = InvalidPortID) override;

    void initState();

  private:
    bool isKernelArg(const std::string &arg);
    void mapMemory();
    size_t getArgc() const;
    void writeRemote(Addr dest, const uint8_t *data, size_t size);
    void writeArg(Addr &args, size_t &i, Addr argv, const char *cmd, const char *begin);
    Addr loadModule(const std::string &path, const std::string &name, Addr addr);
};

#endif
<|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

#if defined TORRENT_DEBUG_BUFFERS && !defined TORRENT_DISABLE_POOL_ALLOCATORS
#error TORRENT_DEBUG_BUFFERS only works if you also disable pool allocators
#endif

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

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

// ======= GCC =========

#if defined __GNUC__

# if __GNUC__ >= 3
#  define TORRENT_DEPRECATED __attribute__ ((deprecated))
# endif

// GCC pre 4.0 did not have support for the visibility attribute
# if __GNUC__ >= 4
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __attribute__ ((visibility("default")))
#  endif
# endif

// ======= SUNPRO =========

#elif defined __SUNPRO_CC

# if __SUNPRO_CC >= 0x550
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __global
#  endif
# endif

// SunPRO seems to have an overly-strict
// definition of POD types and doesn't
// seem to allow boost::array in unions
#define TORRENT_BROKEN_UNIONS 1

// ======= MSVC =========

#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)
# endif

#define TORRENT_DEPRECATED_PREFIX __declspec(deprecated)

#endif

// ======= PLATFORMS =========

// set up defines for target environments
// ==== AMIGA ===
#if defined __AMIGA__ || defined __amigaos__ || defined __AROS__
#define TORRENT_AMIGA
#define TORRENT_USE_MLOCK 0
#define TORRENT_USE_WRITEV 0
#define TORRENT_USE_READV 0
#define TORRENT_USE_IPV6 0
#define TORRENT_USE_BOOST_THREAD 0
#define TORRENT_USE_IOSTREAM 0
// set this to 1 to disable all floating point operations
// (disables some float-dependent APIs)
#define TORRENT_NO_FPU 1
#define TORRENT_USE_I2P 0
#define TORRENT_USE_ICONV 0

// ==== Darwin/BSD ===
#elif (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \
	|| defined __FreeBSD_kernel__
#define TORRENT_BSD
// we don't need iconv on mac, because
// the locale is always utf-8
#if defined __APPLE__
#define TORRENT_USE_ICONV 0
#endif
#define TORRENT_HAS_FALLOCATE 0

// ==== LINUX ===
#elif defined __linux__
#define TORRENT_LINUX

// ==== MINGW ===
#elif defined __MINGW32__
#define TORRENT_MINGW
#define TORRENT_WINDOWS
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_RLIMIT 0

// ==== WINDOWS ===
#elif defined WIN32
#define TORRENT_WINDOWS
// windows has its own functions to convert
// apple uses utf-8 as its locale, so no conversion
// is necessary
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_RLIMIT 0
#define TORRENT_HAS_FALLOCATE 0

// ==== SOLARIS ===
#elif defined sun || defined __sun
#define TORRENT_SOLARIS
#define TORRENT_COMPLETE_TYPES_REQUIRED 1

// ==== BEOS ===
#elif defined __BEOS__ || defined __HAIKU__
#define TORRENT_BEOS
#include <storage/StorageDefs.h> // B_PATH_NAME_LENGTH
#define TORRENT_HAS_FALLOCATE 0
#define TORRENT_USE_MLOCK 0
#define TORRENT_USE_ICONV 0
#if __GNUCC__ == 2
# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# endif
#endif
#else
#warning unknown OS, assuming BSD
#define TORRENT_BSD
#endif

// on windows, NAME_MAX refers to Unicode characters
// on linux it refers to bytes (utf-8 encoded)
// TODO: Make this count Unicode characters instead of bytes on windows

// windows
#if defined FILENAME_MAX
#define TORRENT_MAX_PATH FILENAME_MAX

// beos
#elif defined B_PATH_NAME_LENGTH
#define TORRENT_MAX_PATH B_PATH_NAME_LENGTH

// solaris
#elif defined MAXPATH
#define TORRENT_MAX_PATH MAXPATH

// posix
#elif defined NAME_MAX
#define TORRENT_MAX_PATH NAME_MAX

// none of the above
#else
// this is the maximum number of characters in a
// path element / filename on windows
#define TORRENT_MAX_PATH 255
#warning unknown platform, assuming the longest path is 255

#endif

#if defined TORRENT_WINDOWS && !defined TORRENT_MINGW

// class X needs to have dll-interface to be used by clients of class Y
#pragma warning(disable:4251)
// '_vsnprintf': This function or variable may be unsafe
#pragma warning(disable:4996)

#include <stdarg.h>

inline int snprintf(char* buf, int len, char const* fmt, ...)
{
	va_list lp;
	va_start(lp, fmt);
	int ret = _vsnprintf(buf, len, fmt, lp);
	va_end(lp);
	if (ret < 0) { buf[len-1] = 0; ret = len-1; }
	return ret;
}

#define strtoll _strtoi64
#else
#include <limits.h>
#endif

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

// libiconv presence, not implemented yet
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 1
#endif

#ifndef TORRENT_BROKEN_UNIONS
#define TORRENT_BROKEN_UNIONS 0
#endif

#if defined UNICODE && !defined BOOST_NO_STD_WSTRING
#define TORRENT_USE_WSTRING 1
#else
#define TORRENT_USE_WSTRING 0
#endif // UNICODE

#ifndef TORRENT_HAS_FALLOCATE
#define TORRENT_HAS_FALLOCATE 1
#endif

#ifndef TORRENT_EXPORT
# define TORRENT_EXPORT
#endif

#ifndef TORRENT_DEPRECATED_PREFIX
#define TORRENT_DEPRECATED_PREFIX
#endif

#ifndef TORRENT_DEPRECATED
#define TORRENT_DEPRECATED
#endif

#ifndef TORRENT_COMPLETE_TYPES_REQUIRED
#define TORRENT_COMPLETE_TYPES_REQUIRED 0
#endif

#ifndef TORRENT_USE_RLIMIT
#define TORRENT_USE_RLIMIT 1
#endif

#ifndef TORRENT_USE_IPV6
#define TORRENT_USE_IPV6 1
#endif

#ifndef TORRENT_USE_MLOCK
#define TORRENT_USE_MLOCK 1
#endif

#ifndef TORRENT_USE_WRITEV
#define TORRENT_USE_WRITEV 1
#endif

#ifndef TORRENT_USE_READV
#define TORRENT_USE_READV 1
#endif

#ifndef TORRENT_NO_FPU
#define TORRENT_NO_FPU 0
#endif

#if !defined TORRENT_USE_IOSTREAM && !defined BOOST_NO_IOSTREAM
#define TORRENT_USE_IOSTREAM 1
#else
#define TORRENT_USE_IOSTREAM 0
#endif

#ifndef TORRENT_USE_I2P
#define TORRENT_USE_I2P 1
#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

#if defined _MSC_VER && _MSC_VER <= 1200
#define for if (false) {} else for
#endif

#if TORRENT_BROKEN_UNIONS
#define TORRENT_UNION struct
#else
#define TORRENT_UNION union
#endif

// determine what timer implementation we can use
// if one is already defined, don't pick one
// autmatically. This lets the user control this
// from the Jamfile
#if !defined TORRENT_USE_ABSOLUTE_TIME \
	&& !defined TORRENT_USE_QUERY_PERFORMANCE_TIMER \
	&& !defined TORRENT_USE_CLOCK_GETTIME \
	&& !defined TORRENT_USE_BOOST_DATE_TIME \
	&& !defined TORRENT_USE_ECLOCK \
	&& !defined TORRENT_USE_SYSTEM_TIME

#if defined(__MACH__)
#define TORRENT_USE_ABSOLUTE_TIME 1
#elif defined(_WIN32) || defined TORRENT_MINGW
#define TORRENT_USE_QUERY_PERFORMANCE_TIMER 1
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
#define TORRENT_USE_CLOCK_GETTIME 1
#elif defined(TORRENT_AMIGA)
#define TORRENT_USE_ECLOCK 1
#elif defined(TORRENT_BEOS)
#define TORRENT_USE_SYSTEM_TIME 1
#else
#define TORRENT_USE_BOOST_DATE_TIME 1
#endif

#endif

#endif // TORRENT_CONFIG_HPP_INCLUDED

<commit_msg>fixed typo in config relating to buffer debug builds<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

#if defined TORRENT_DEBUG_BUFFERS && !defined TORRENT_DISABLE_POOL_ALLOCATOR
#error TORRENT_DEBUG_BUFFERS only works if you also disable pool allocators
#endif

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

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

// ======= GCC =========

#if defined __GNUC__

# if __GNUC__ >= 3
#  define TORRENT_DEPRECATED __attribute__ ((deprecated))
# endif

// GCC pre 4.0 did not have support for the visibility attribute
# if __GNUC__ >= 4
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __attribute__ ((visibility("default")))
#  endif
# endif

// ======= SUNPRO =========

#elif defined __SUNPRO_CC

# if __SUNPRO_CC >= 0x550
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __global
#  endif
# endif

// SunPRO seems to have an overly-strict
// definition of POD types and doesn't
// seem to allow boost::array in unions
#define TORRENT_BROKEN_UNIONS 1

// ======= MSVC =========

#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)
# endif

#define TORRENT_DEPRECATED_PREFIX __declspec(deprecated)

#endif

// ======= PLATFORMS =========

// set up defines for target environments
// ==== AMIGA ===
#if defined __AMIGA__ || defined __amigaos__ || defined __AROS__
#define TORRENT_AMIGA
#define TORRENT_USE_MLOCK 0
#define TORRENT_USE_WRITEV 0
#define TORRENT_USE_READV 0
#define TORRENT_USE_IPV6 0
#define TORRENT_USE_BOOST_THREAD 0
#define TORRENT_USE_IOSTREAM 0
// set this to 1 to disable all floating point operations
// (disables some float-dependent APIs)
#define TORRENT_NO_FPU 1
#define TORRENT_USE_I2P 0
#define TORRENT_USE_ICONV 0

// ==== Darwin/BSD ===
#elif (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \
	|| defined __FreeBSD_kernel__
#define TORRENT_BSD
// we don't need iconv on mac, because
// the locale is always utf-8
#if defined __APPLE__
#define TORRENT_USE_ICONV 0
#endif
#define TORRENT_HAS_FALLOCATE 0

// ==== LINUX ===
#elif defined __linux__
#define TORRENT_LINUX

// ==== MINGW ===
#elif defined __MINGW32__
#define TORRENT_MINGW
#define TORRENT_WINDOWS
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_RLIMIT 0

// ==== WINDOWS ===
#elif defined WIN32
#define TORRENT_WINDOWS
// windows has its own functions to convert
// apple uses utf-8 as its locale, so no conversion
// is necessary
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_RLIMIT 0
#define TORRENT_HAS_FALLOCATE 0

// ==== SOLARIS ===
#elif defined sun || defined __sun
#define TORRENT_SOLARIS
#define TORRENT_COMPLETE_TYPES_REQUIRED 1

// ==== BEOS ===
#elif defined __BEOS__ || defined __HAIKU__
#define TORRENT_BEOS
#include <storage/StorageDefs.h> // B_PATH_NAME_LENGTH
#define TORRENT_HAS_FALLOCATE 0
#define TORRENT_USE_MLOCK 0
#define TORRENT_USE_ICONV 0
#if __GNUCC__ == 2
# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# endif
#endif
#else
#warning unknown OS, assuming BSD
#define TORRENT_BSD
#endif

// on windows, NAME_MAX refers to Unicode characters
// on linux it refers to bytes (utf-8 encoded)
// TODO: Make this count Unicode characters instead of bytes on windows

// windows
#if defined FILENAME_MAX
#define TORRENT_MAX_PATH FILENAME_MAX

// beos
#elif defined B_PATH_NAME_LENGTH
#define TORRENT_MAX_PATH B_PATH_NAME_LENGTH

// solaris
#elif defined MAXPATH
#define TORRENT_MAX_PATH MAXPATH

// posix
#elif defined NAME_MAX
#define TORRENT_MAX_PATH NAME_MAX

// none of the above
#else
// this is the maximum number of characters in a
// path element / filename on windows
#define TORRENT_MAX_PATH 255
#warning unknown platform, assuming the longest path is 255

#endif

#if defined TORRENT_WINDOWS && !defined TORRENT_MINGW

// class X needs to have dll-interface to be used by clients of class Y
#pragma warning(disable:4251)
// '_vsnprintf': This function or variable may be unsafe
#pragma warning(disable:4996)

#include <stdarg.h>

inline int snprintf(char* buf, int len, char const* fmt, ...)
{
	va_list lp;
	va_start(lp, fmt);
	int ret = _vsnprintf(buf, len, fmt, lp);
	va_end(lp);
	if (ret < 0) { buf[len-1] = 0; ret = len-1; }
	return ret;
}

#define strtoll _strtoi64
#else
#include <limits.h>
#endif

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

// libiconv presence, not implemented yet
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 1
#endif

#ifndef TORRENT_BROKEN_UNIONS
#define TORRENT_BROKEN_UNIONS 0
#endif

#if defined UNICODE && !defined BOOST_NO_STD_WSTRING
#define TORRENT_USE_WSTRING 1
#else
#define TORRENT_USE_WSTRING 0
#endif // UNICODE

#ifndef TORRENT_HAS_FALLOCATE
#define TORRENT_HAS_FALLOCATE 1
#endif

#ifndef TORRENT_EXPORT
# define TORRENT_EXPORT
#endif

#ifndef TORRENT_DEPRECATED_PREFIX
#define TORRENT_DEPRECATED_PREFIX
#endif

#ifndef TORRENT_DEPRECATED
#define TORRENT_DEPRECATED
#endif

#ifndef TORRENT_COMPLETE_TYPES_REQUIRED
#define TORRENT_COMPLETE_TYPES_REQUIRED 0
#endif

#ifndef TORRENT_USE_RLIMIT
#define TORRENT_USE_RLIMIT 1
#endif

#ifndef TORRENT_USE_IPV6
#define TORRENT_USE_IPV6 1
#endif

#ifndef TORRENT_USE_MLOCK
#define TORRENT_USE_MLOCK 1
#endif

#ifndef TORRENT_USE_WRITEV
#define TORRENT_USE_WRITEV 1
#endif

#ifndef TORRENT_USE_READV
#define TORRENT_USE_READV 1
#endif

#ifndef TORRENT_NO_FPU
#define TORRENT_NO_FPU 0
#endif

#if !defined TORRENT_USE_IOSTREAM && !defined BOOST_NO_IOSTREAM
#define TORRENT_USE_IOSTREAM 1
#else
#define TORRENT_USE_IOSTREAM 0
#endif

#ifndef TORRENT_USE_I2P
#define TORRENT_USE_I2P 1
#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

#if defined _MSC_VER && _MSC_VER <= 1200
#define for if (false) {} else for
#endif

#if TORRENT_BROKEN_UNIONS
#define TORRENT_UNION struct
#else
#define TORRENT_UNION union
#endif

// determine what timer implementation we can use
// if one is already defined, don't pick one
// autmatically. This lets the user control this
// from the Jamfile
#if !defined TORRENT_USE_ABSOLUTE_TIME \
	&& !defined TORRENT_USE_QUERY_PERFORMANCE_TIMER \
	&& !defined TORRENT_USE_CLOCK_GETTIME \
	&& !defined TORRENT_USE_BOOST_DATE_TIME \
	&& !defined TORRENT_USE_ECLOCK \
	&& !defined TORRENT_USE_SYSTEM_TIME

#if defined(__MACH__)
#define TORRENT_USE_ABSOLUTE_TIME 1
#elif defined(_WIN32) || defined TORRENT_MINGW
#define TORRENT_USE_QUERY_PERFORMANCE_TIMER 1
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
#define TORRENT_USE_CLOCK_GETTIME 1
#elif defined(TORRENT_AMIGA)
#define TORRENT_USE_ECLOCK 1
#elif defined(TORRENT_BEOS)
#define TORRENT_USE_SYSTEM_TIME 1
#else
#define TORRENT_USE_BOOST_DATE_TIME 1
#endif

#endif

#endif // TORRENT_CONFIG_HPP_INCLUDED

<|endoftext|>


<commit_before>/*
 * Author: doe300
 *
 * See the file "LICENSE" for the full license governing this code.
 */

#include "CodeGenerator.h"

#include "../InstructionWalker.h"
#include "../Module.h"
#include "../Profiler.h"
#include "GraphColoring.h"
#include "KernelInfo.h"
#include "log.h"
#include "../../lib/vc4asm/src/Validator.h"

#include <assert.h>
#include <climits>
#include <map>
#include <sstream>

using namespace vc4c;
using namespace vc4c::qpu_asm;
using namespace vc4c::intermediate;

CodeGenerator::CodeGenerator(const Module& module, const Configuration& config) : config(config), module(module) {}

static FastMap<const Local*, std::size_t> mapLabels(Method& method)
{
    logging::debug() << "-----" << logging::endl;
    FastMap<const Local*, std::size_t> labelsMap;
    labelsMap.reserve(method.size());
    // index is in bytes, so an increment of 1 instructions, increments by 8 bytes
    std::size_t index = 0;
    auto it = method.walkAllInstructions();
    while(!it.isEndOfMethod())
    {
        BranchLabel* label = it.isEndOfBlock() ? nullptr : it.get<BranchLabel>();
        if(label != nullptr)
        {
            logging::debug() << "Mapping label '" << label->getLabel()->name << "' to byte-position " << index
                             << logging::endl;
            labelsMap[label->getLabel()] = index;

            it.nextInMethod();
        }
        else if(!it.isEndOfBlock() && it.has() && !it->mapsToASMInstruction())
        {
            // an instruction which has no equivalent in machine code -> drop
            logging::debug() << "Dropping instruction not mapped to assembler: " << it->to_string() << logging::endl;
            it.erase();
        }
        else
        {
            index += 8;
            it.nextInMethod();
        }
        if(it.isEndOfBlock() && !it.isEndOfMethod())
            // this handles empty basic blocks, so the index is not incremented in the next iteration
            it.nextInMethod();
    }
    logging::debug() << "Mapped " << labelsMap.size() << " labels to positions" << logging::endl;

    return labelsMap;
}

const FastModificationList<std::unique_ptr<qpu_asm::Instruction>>& CodeGenerator::generateInstructions(Method& method)
{
    PROFILE_COUNTER(vc4c::profiler::COUNTER_BACKEND + 0, "CodeGeneration (before)", method.countInstructions());
#ifdef MULTI_THREADED
    instructionsLock.lock();
#endif
    auto& generatedInstructions = allInstructions[&method];
#ifdef MULTI_THREADED
    instructionsLock.unlock();
#endif

    // check and fix possible errors with register-association
    PROFILE_START(initializeLocalsUses);
    GraphColoring coloring(method, method.walkAllInstructions());
    PROFILE_END(initializeLocalsUses);
    PROFILE_START(colorGraph);
    std::size_t round = 0;
    while(round < config.additionalOptions.registerResolverMaxRounds && !coloring.colorGraph())
    {
        if(coloring.fixErrors())
            break;
        ++round;
    }
    if(round >= config.additionalOptions.registerResolverMaxRounds)
    {
        logging::warn() << "Register conflict resolver has exceeded its maximum rounds, there might still be errors!"
                        << logging::endl;
    }
    PROFILE_END(colorGraph);

    // create label-map + remove labels
    const auto labelMap = mapLabels(method);

    // IMPORTANT: DO NOT OPTIMIZE, RE-ORDER, COMBINE, INSERT OR REMOVE ANY INSTRUCTION AFTER THIS POINT!!!
    // otherwise, labels/branches will be wrong

    // map to registers
    PROFILE_START(toRegisterMap);
    PROFILE_START(toRegisterMapGraph);
    auto registerMapping = coloring.toRegisterMap();
    PROFILE_END(toRegisterMapGraph);
    PROFILE_END(toRegisterMap);

    logging::debug() << "-----" << logging::endl;
    std::size_t index = 0;

    std::string s = "";

    for(auto bb_it = method.begin(); bb_it != method.end(); ++bb_it)
    {
        auto it = bb_it->begin();
        if(it.getBasicBlock()->empty())
        {
            s = s.empty() ? bb_it->getLabel()->to_string() : s + "," + bb_it->getLabel()->to_string();
            continue;
        }

        auto label = dynamic_cast<intermediate::BranchLabel*>(it.get());
        assert(label != nullptr);
        it.nextInBlock();

        auto instr = it.get();
        if(instr->mapsToASMInstruction())
        {
            Instruction* mapped = instr->convertToAsm(registerMapping, labelMap, index);
            if(mapped != nullptr)
            {
                mapped->previousComment += s.empty() ? label->to_string() : s + ", " + label->to_string();
                s = "";
                generatedInstructions.emplace_back(mapped);
            }
            ++index;
        }

        it.nextInBlock();

        while(!it.isEndOfBlock())
        {
            auto instr = it.get();
            if(instr->mapsToASMInstruction())
            {
                Instruction* mapped = instr->convertToAsm(registerMapping, labelMap, index);
                if(mapped != nullptr)
                {
                    generatedInstructions.emplace_back(mapped);
                }
                ++index;
            }

            it.nextInBlock();
        }
    }

    logging::debug() << "-----" << logging::endl;
    index = 0;
    for(const auto& instr : generatedInstructions)
    {
        CPPLOG_LAZY(
            logging::Level::DEBUG, log << std::hex << index << " " << instr->toHexString(true) << logging::endl);
        index += 8;
    }
    logging::debug() << "Generated " << std::dec << generatedInstructions.size() << " instructions!" << logging::endl;

    PROFILE_COUNTER_WITH_PREV(vc4c::profiler::COUNTER_BACKEND + 1000, "CodeGeneration (after)",
        generatedInstructions.size(), vc4c::profiler::COUNTER_BACKEND + 0);
    return generatedInstructions;
}

std::size_t CodeGenerator::writeOutput(std::ostream& stream)
{
    ModuleInfo moduleInfo;

    std::size_t maxStackSize = 0;
    for(const auto& m : module)
        maxStackSize = std::max(maxStackSize, m->calculateStackSize() * m->metaData.getWorkGroupSize());
    if(maxStackSize / sizeof(uint64_t) > std::numeric_limits<uint16_t>::max() || maxStackSize % sizeof(uint64_t) != 0)
        throw CompilationError(
            CompilationStep::CODE_GENERATION, "Stack-frame has unsupported size of", std::to_string(maxStackSize));
    moduleInfo.setStackFrameSize(Word(Byte(maxStackSize)));

    std::size_t numBytes = 0;
    // initial offset is zero
    std::size_t offset = 0;
    if(config.writeKernelInfo)
    {
        moduleInfo.kernelInfos.reserve(allInstructions.size());
        // generate kernel-infos
        for(const auto& pair : allInstructions)
        {
            moduleInfo.addKernelInfo(getKernelInfos(*pair.first, offset, pair.second.size()));
            offset += pair.second.size();
        }
        // add global offset (size of  header)
        std::ostringstream dummyStream;
        offset = moduleInfo.write(dummyStream, config.outputMode, module.globalData, Byte(maxStackSize));

        for(KernelInfo& info : moduleInfo.kernelInfos)
            info.setOffset(info.getOffset() + Word(offset));
    }
    // prepend module header to output
    // also write, if writeKernelInfo is not set, since global-data is written in here too
    logging::debug() << "Writing module header..." << logging::endl;
    numBytes += moduleInfo.write(stream, config.outputMode, module.globalData, Byte(maxStackSize)) * sizeof(uint64_t);

    for(const auto& pair : allInstructions)
    {
        switch(config.outputMode)
        {
        case OutputMode::ASSEMBLER:
            for(const auto& instr : pair.second)
            {
                stream << instr->toASMString() << std::endl;
                numBytes += 0; // doesn't matter here, since the number of bytes is unused for assembler output
            }
            break;
        case OutputMode::BINARY:
            for(const auto& instr : pair.second)
            {
                const uint64_t binary = instr->toBinaryCode();
                stream.write(reinterpret_cast<const char*>(&binary), 8);
                numBytes += 8;
            }
            break;
        case OutputMode::HEX:
            for(const auto& instr : pair.second)
            {
                stream << instr->toHexString(true) << std::endl;
                numBytes += 8; // doesn't matter here, since the number of bytes is unused for hexadecimal output
            }
        }
    }
    stream.flush();
    return numBytes;
}

// register/instruction mapping
void CodeGenerator::toMachineCode(Method& kernel)
{
    kernel.cleanLocals();
    const auto& instructions = generateInstructions(kernel);
#ifdef VERIFIER_HEADER
    std::vector<uint64_t> hexData;
    hexData.reserve(instructions.size());
    for(const auto& instr : instructions)
    {
        hexData.push_back(instr->toBinaryCode());
    }

    Validator v;
    v.OnMessage = [&instructions](const Message& msg) -> void {
        const auto & validatorMessage = dynamic_cast<const Validator::Message&>(msg);
        if(validatorMessage.Loc >= 0)
        {
            auto it = instructions.begin();
            std::advance(it, validatorMessage.Loc);
            logging::error() << "Validation-error '" << validatorMessage.Text << "' in: " << (*it)->toASMString()
                             << logging::endl;
            if(validatorMessage.RefLoc >= 0)
            {
                it = instructions.begin();
                std::advance(it, validatorMessage.RefLoc);
                logging::error() << "With reference to instruction: " << (*it)->toASMString() << logging::endl;
            }
        }

        throw CompilationError(CompilationStep::VERIFIER, "vc4asm verification error", msg.toString());
    };
    v.Instructions = &hexData;
    logging::info() << "Validation-output: " << logging::endl;
    v.Validate();
    fflush(stderr);
#endif
}
<commit_msg>Add: surpress exceptions when `--no-safe-stop` is enabled<commit_after>/*
 * Author: doe300
 *
 * See the file "LICENSE" for the full license governing this code.
 */

#include "CodeGenerator.h"

#include "../InstructionWalker.h"
#include "../Module.h"
#include "../Profiler.h"
#include "GraphColoring.h"
#include "KernelInfo.h"
#include "log.h"
#include "../../lib/vc4asm/src/Validator.h"

#include <assert.h>
#include <climits>
#include <map>
#include <sstream>

using namespace vc4c;
using namespace vc4c::qpu_asm;
using namespace vc4c::intermediate;

CodeGenerator::CodeGenerator(const Module& module, const Configuration& config) : config(config), module(module) {}

static FastMap<const Local*, std::size_t> mapLabels(Method& method)
{
    logging::debug() << "-----" << logging::endl;
    FastMap<const Local*, std::size_t> labelsMap;
    labelsMap.reserve(method.size());
    // index is in bytes, so an increment of 1 instructions, increments by 8 bytes
    std::size_t index = 0;
    auto it = method.walkAllInstructions();
    while(!it.isEndOfMethod())
    {
        BranchLabel* label = it.isEndOfBlock() ? nullptr : it.get<BranchLabel>();
        if(label != nullptr)
        {
            logging::debug() << "Mapping label '" << label->getLabel()->name << "' to byte-position " << index
                             << logging::endl;
            labelsMap[label->getLabel()] = index;

            it.nextInMethod();
        }
        else if(!it.isEndOfBlock() && it.has() && !it->mapsToASMInstruction())
        {
            // an instruction which has no equivalent in machine code -> drop
            logging::debug() << "Dropping instruction not mapped to assembler: " << it->to_string() << logging::endl;
            it.erase();
        }
        else
        {
            index += 8;
            it.nextInMethod();
        }
        if(it.isEndOfBlock() && !it.isEndOfMethod())
            // this handles empty basic blocks, so the index is not incremented in the next iteration
            it.nextInMethod();
    }
    logging::debug() << "Mapped " << labelsMap.size() << " labels to positions" << logging::endl;

    return labelsMap;
}

const FastModificationList<std::unique_ptr<qpu_asm::Instruction>>& CodeGenerator::generateInstructions(Method& method)
{
    PROFILE_COUNTER(vc4c::profiler::COUNTER_BACKEND + 0, "CodeGeneration (before)", method.countInstructions());
#ifdef MULTI_THREADED
    instructionsLock.lock();
#endif
    auto& generatedInstructions = allInstructions[&method];
#ifdef MULTI_THREADED
    instructionsLock.unlock();
#endif

    // check and fix possible errors with register-association
    PROFILE_START(initializeLocalsUses);
    GraphColoring coloring(method, method.walkAllInstructions());
    PROFILE_END(initializeLocalsUses);
    PROFILE_START(colorGraph);
    std::size_t round = 0;
    while(round < config.additionalOptions.registerResolverMaxRounds && !coloring.colorGraph())
    {
        if(coloring.fixErrors())
            break;
        ++round;
    }
    if(round >= config.additionalOptions.registerResolverMaxRounds)
    {
        logging::warn() << "Register conflict resolver has exceeded its maximum rounds, there might still be errors!"
                        << logging::endl;
    }
    PROFILE_END(colorGraph);

    // create label-map + remove labels
    const auto labelMap = mapLabels(method);

    // IMPORTANT: DO NOT OPTIMIZE, RE-ORDER, COMBINE, INSERT OR REMOVE ANY INSTRUCTION AFTER THIS POINT!!!
    // otherwise, labels/branches will be wrong

    // map to registers
    PROFILE_START(toRegisterMap);
    PROFILE_START(toRegisterMapGraph);
    auto registerMapping = coloring.toRegisterMap();
    PROFILE_END(toRegisterMapGraph);
    PROFILE_END(toRegisterMap);

    logging::debug() << "-----" << logging::endl;
    std::size_t index = 0;

    std::string s = "";

    for(auto bb_it = method.begin(); bb_it != method.end(); ++bb_it)
    {
        auto it = bb_it->begin();
        if(it.getBasicBlock()->empty())
        {
            s = s.empty() ? bb_it->getLabel()->to_string() : s + "," + bb_it->getLabel()->to_string();
            continue;
        }

        auto label = dynamic_cast<intermediate::BranchLabel*>(it.get());
        assert(label != nullptr);
        it.nextInBlock();

        auto instr = it.get();
        if(instr->mapsToASMInstruction())
        {
            Instruction* mapped = instr->convertToAsm(registerMapping, labelMap, index);
            if(mapped != nullptr)
            {
                mapped->previousComment += s.empty() ? label->to_string() : s + ", " + label->to_string();
                s = "";
                generatedInstructions.emplace_back(mapped);
            }
            ++index;
        }

        it.nextInBlock();

        while(!it.isEndOfBlock())
        {
            auto instr = it.get();
            if(instr->mapsToASMInstruction())
            {
                Instruction* mapped = instr->convertToAsm(registerMapping, labelMap, index);
                if(mapped != nullptr)
                {
                    generatedInstructions.emplace_back(mapped);
                }
                ++index;
            }

            it.nextInBlock();
        }
    }

    logging::debug() << "-----" << logging::endl;
    index = 0;
    for(const auto& instr : generatedInstructions)
    {
        CPPLOG_LAZY(
            logging::Level::DEBUG, log << std::hex << index << " " << instr->toHexString(true) << logging::endl);
        index += 8;
    }
    logging::debug() << "Generated " << std::dec << generatedInstructions.size() << " instructions!" << logging::endl;

    PROFILE_COUNTER_WITH_PREV(vc4c::profiler::COUNTER_BACKEND + 1000, "CodeGeneration (after)",
        generatedInstructions.size(), vc4c::profiler::COUNTER_BACKEND + 0);
    return generatedInstructions;
}

std::size_t CodeGenerator::writeOutput(std::ostream& stream)
{
    ModuleInfo moduleInfo;

    std::size_t maxStackSize = 0;
    for(const auto& m : module)
        maxStackSize = std::max(maxStackSize, m->calculateStackSize() * m->metaData.getWorkGroupSize());
    if(maxStackSize / sizeof(uint64_t) > std::numeric_limits<uint16_t>::max() || maxStackSize % sizeof(uint64_t) != 0)
        throw CompilationError(
            CompilationStep::CODE_GENERATION, "Stack-frame has unsupported size of", std::to_string(maxStackSize));
    moduleInfo.setStackFrameSize(Word(Byte(maxStackSize)));

    std::size_t numBytes = 0;
    // initial offset is zero
    std::size_t offset = 0;
    if(config.writeKernelInfo)
    {
        moduleInfo.kernelInfos.reserve(allInstructions.size());
        // generate kernel-infos
        for(const auto& pair : allInstructions)
        {
            moduleInfo.addKernelInfo(getKernelInfos(*pair.first, offset, pair.second.size()));
            offset += pair.second.size();
        }
        // add global offset (size of  header)
        std::ostringstream dummyStream;
        offset = moduleInfo.write(dummyStream, config.outputMode, module.globalData, Byte(maxStackSize));

        for(KernelInfo& info : moduleInfo.kernelInfos)
            info.setOffset(info.getOffset() + Word(offset));
    }
    // prepend module header to output
    // also write, if writeKernelInfo is not set, since global-data is written in here too
    logging::debug() << "Writing module header..." << logging::endl;
    numBytes += moduleInfo.write(stream, config.outputMode, module.globalData, Byte(maxStackSize)) * sizeof(uint64_t);

    for(const auto& pair : allInstructions)
    {
        switch(config.outputMode)
        {
        case OutputMode::ASSEMBLER:
            for(const auto& instr : pair.second)
            {
                stream << instr->toASMString() << std::endl;
                numBytes += 0; // doesn't matter here, since the number of bytes is unused for assembler output
            }
            break;
        case OutputMode::BINARY:
            for(const auto& instr : pair.second)
            {
                const uint64_t binary = instr->toBinaryCode();
                stream.write(reinterpret_cast<const char*>(&binary), 8);
                numBytes += 8;
            }
            break;
        case OutputMode::HEX:
            for(const auto& instr : pair.second)
            {
                stream << instr->toHexString(true) << std::endl;
                numBytes += 8; // doesn't matter here, since the number of bytes is unused for hexadecimal output
            }
        }
    }
    stream.flush();
    return numBytes;
}

// register/instruction mapping
void CodeGenerator::toMachineCode(Method& kernel)
{
    kernel.cleanLocals();
    const auto& instructions = generateInstructions(kernel);
#ifdef VERIFIER_HEADER
    std::vector<uint64_t> hexData;
    hexData.reserve(instructions.size());
    for(const auto& instr : instructions)
    {
        hexData.push_back(instr->toBinaryCode());
    }

    Validator v;
    v.OnMessage = [&instructions, this](const Message& msg) -> void {
        const auto & validatorMessage = dynamic_cast<const Validator::Message&>(msg);
        if(validatorMessage.Loc >= 0)
        {
            auto it = instructions.begin();
            std::advance(it, validatorMessage.Loc);
            logging::error() << "Validation-error '" << validatorMessage.Text << "' in: " << (*it)->toASMString()
                             << logging::endl;
            if(validatorMessage.RefLoc >= 0)
            {
                it = instructions.begin();
                std::advance(it, validatorMessage.RefLoc);
                logging::error() << "With reference to instruction: " << (*it)->toASMString() << logging::endl;
            }
        }
        if (config.stopWhenVerificationFailed)
            throw CompilationError(CompilationStep::VERIFIER, "vc4asm verification error", msg.toString());
    };
    v.Instructions = &hexData;
    logging::info() << "Validation-output: " << logging::endl;
    v.Validate();
    fflush(stderr);
#endif
}
<|endoftext|>


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

#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include "grovemd.h"
#include "jhd1313m1.h"
#include "rfr359f.h"
#include "hmc5883l.h"
#include "grovevdiv.h"

using namespace std;
using namespace upm;

mutex crit;
bool running = true;

bool blockedFL = false;
bool blockedFR = false;
bool blockedRL = false;
bool blockedRR = false;

bool batteryLow = true;
const float batteryThreshold = 7.2f;

const string heading = "--|--N--|--|--E--|--|--S--|--|--W--|--|--N--|--";

// Handler for POSIX signals
void signalHandler(int signo)
{
  if (signo == SIGINT){
    running = false;
  }
}

// Heading display on LCD
void displayHeading(Jhd1313m1 *lcd, Hmc5883l *compass){

    // You can set your declination in radians for more accurate readings
    //compass->set_declination(0.2749);

    while(running){
        compass->update();

        // Round the heading returned by compass and turn it into an index
        // from 0 to 36 for the heading string
        int hdg = int(compass->heading() + 0.5f);
        int hdg_index = hdg / 10;

        // Write the heading on the first line, lcd->clear() is not needed since
        // we write the entire line
        crit.lock();
        lcd->setCursor(0, 0);
        lcd->write("HDG: " + heading.substr(hdg_index, 11));
        crit.unlock();

        // Update readings and display every 250 ms
        usleep(250000);
    }
}

// Battery level display on LCD
void displayBattery(Jhd1313m1 *lcd, GroveVDiv *divider){

    // Variable used for flashing LCD red when battery is low
    uint8_t red = 0x3F;

    while(running){
        // Read 50 samples each with 2 ms in between (100 ms total)
        int avgValue = divider->value(50);
        // Convert the value to voltage at 3x gain and 5V reference
        // Also subtract half a unit for improved accuracy in the 6~8V range
        float voltage = divider->computedValue(3, avgValue) - 0.5f;
        string displayStr = to_string(voltage);
        displayStr = displayStr.substr(0, 4);

        // Write the battery voltage on the second line of the display
        crit.lock();
        lcd->setCursor(1, 0);
        lcd->write("Batt: " + displayStr + " V    ");
        crit.unlock();

        // Battery low, flash LCD and refresh more often
        if(voltage < 7.2f)
        {
            batteryLow = true;
            lcd->setColor(red, 0x00, 0x00);
            // Toggle red bits
            red = ~red;
            sleep(2);
        }
        else{
            // Battery was considered low but new reading is above threshold
            // Thus return to normal operation mode and make the LCD green
            if(batteryLow){
                lcd->setColor(0x00, 0xCF, 0x00);
            }
            batteryLow = false;
            // Refresh every 5 seconds
            sleep(5);
        }
    }
}

// IR sensors thread
void distanceIR(GroveMD *motors, RFR359F *fl, RFR359F *fr, RFR359F *rl, RFR359F *rr){
    while(running){
        // Set the corresponding sensor variable when an object is detected
        if(fl->objectDetected()){
            blockedFL = true;
        }
        else{
            blockedFL = false;
        }
        if(fr->objectDetected()){
            blockedFR = true;
        }
        else{
            blockedFR = false;
        }
        if(rl->objectDetected()){
            blockedRL = true;
        }
        else{
            blockedRL = false;
        }
        if(rr->objectDetected()){
            blockedRR = true;
        }
        else{
            blockedRR = false;
        }
        // Stop the motors if any sensor was triggered
        if(blockedFL || blockedFR || blockedRL || blockedRR){
            motors->setMotorSpeeds(0, 0);
        }
        // Refresh every 10 ms
        usleep(10000);
    }
}

int main(int argc, char **argv)
{
  // Register signal handler
  signal(SIGINT, signalHandler);

  // Instantiate an I2C Grove Motor Driver on default I2C bus
  GroveMD *motors = new GroveMD(GROVEMD_I2C_BUS, GROVEMD_DEFAULT_I2C_ADDR);
  if(motors == NULL){
      cerr << "Failed to initialize the motor driver." << endl;
      exit(EXIT_FAILURE);
  }

  // Initialize the Grove RGB Backlit LCD using implicit
  // 0x62 for RGB_ADDRESS and 0x3E for LCD_ADDRESS
  Jhd1313m1 *lcd = new upm::Jhd1313m1(0);
  if(lcd == NULL){
      cerr << "Failed to initialize the LCD." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate the HMC5883 compass on default bus
  Hmc5883l *compass = new Hmc5883l(0);
  if(compass == NULL){
      cerr << "Failed to initialize the HMC5883 compass." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate the Grove Voltage Divider on pin A0
  GroveVDiv *divider = new GroveVDiv(0);
  if(divider == NULL){
      cerr << "Failed to initialize the voltage divider." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate 4 Grove IR Distance Interrupters on pins D2, D4, D6, D8
  RFR359F *frontLeftIR = new RFR359F(2);
  RFR359F *frontRightIR = new RFR359F(4);
  RFR359F *rearLeftIR = new RFR359F(6);
  RFR359F *rearRightIR = new RFR359F(8);

  if(frontLeftIR == NULL || frontRightIR == NULL || rearLeftIR == NULL || rearRightIR == NULL){
      cerr << "Failed to initialize one of the IR sensors." << endl;
      exit(EXIT_FAILURE);
  }

  // Start independent threads for the different components
  thread comp (displayHeading, lcd, compass);
  thread batt (displayBattery, lcd, divider);
  thread collision (distanceIR, motors, frontLeftIR, frontRightIR, rearLeftIR, rearRightIR);

  // Main event and control loop
  // Commands are given through stdin as tuples of the form <CMD_NAME SPEED>
  // Except for the <stop> command and are case sensitive
  while(running){

      string command;
      int speed;

      // Wait command from stdin
      cin.clear();
      cin >> command;
      if(command == "stop" || command.empty()){
          // Stop rover
          motors->setMotorSpeeds(0, 0);
          cout << "Rover stopping!" << endl;
          continue;
      }
      // Read speed
      cin >> speed;
      // Check against non-numbers entered in string
      if(cin.fail()){
          cerr << "Error: Bad input! Please check your command and try again." << endl;
          continue;
      }
      // Check for proper range
      if(speed < 0 || speed > 255){
          cerr << "Error: Speed needs to be between 0 to 255." << endl;
          continue;
      }
      // Direction is set based on command/keyword
      if(command == "fwd" && (!blockedFL || !blockedFR)){
          motors->setMotorDirections(GroveMD::DIR_CW, GroveMD::DIR_CW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover going forward at speed " << speed << endl;
      }
      else if(command == "left"  && (!blockedFL || !blockedRL)){
          motors->setMotorDirections(GroveMD::DIR_CCW, GroveMD::DIR_CW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover turning left at speed " << speed << endl;
      }
      else if(command == "right" && (!blockedFR || !blockedRR)){
          motors->setMotorDirections(GroveMD::DIR_CW, GroveMD::DIR_CCW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover turning right at speed " << speed << endl;
      }
      else if(command == "rev"  && (!blockedRL || !blockedRR)){
          motors->setMotorDirections(GroveMD::DIR_CCW, GroveMD::DIR_CCW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover in reverse at speed " << speed << endl;
      }
      else{
          motors->setMotorSpeeds(0, 0);
          cout << "Command not supported or direction blocked!" << endl;
      }
  }

  // Clean up and exit
  comp.join();
  batt.join();
  collision.join();

  // Turn off LCD
  lcd->setColor(0x00, 0x00, 0x00);
  lcd->clear();

  cout << "Exiting..." << endl;

  delete compass;
  delete divider;
  delete motors;
  return 0;
}
<commit_msg>robotics: updated motor directions and a few other changes<commit_after>/*
 * Author: Mihai T Panu <mihai.tudor.panu@intel.com>
 * Copyright (c) 2015 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include "grovemd.h"
#include "jhd1313m1.h"
#include "rfr359f.h"
#include "hmc5883l.h"
#include "grovevdiv.h"

using namespace std;
using namespace upm;

mutex crit;
bool running = true;

bool blockedFL = false;
bool blockedFR = false;
bool blockedRL = false;
bool blockedRR = false;

bool batteryLow = true;
const float batteryThreshold = 7.2f;

const string heading = "--|--N--|--|--E--|--|--S--|--|--W--|--|--N--|--";

// Handler for POSIX signals
void signalHandler(int signo)
{
  if (signo == SIGINT){
    running = false;
  }
}

// Heading display on LCD
void displayHeading(Jhd1313m1 *lcd, Hmc5883l *compass){

    // You can set your declination in radians for more accurate readings
    //compass->set_declination(0.2749);

    while(running){
        compass->update();

        // Round the heading returned by compass and turn it into an index
        // from 0 to 36 for the heading string
        int hdg = int(compass->heading() + 0.5f);
        int hdg_index = hdg / 10;

        // Write the heading on the first line, lcd->clear() is not needed since
        // we write the entire line
        crit.lock();
        lcd->setCursor(0, 0);
        lcd->write("HDG: " + heading.substr(hdg_index, 11));
        crit.unlock();

        // Update readings and display every 250 ms
        usleep(250000);
    }
}

// Battery level display on LCD
void displayBattery(Jhd1313m1 *lcd, GroveVDiv *divider){

    // Variable used for flashing LCD red when battery is low
    uint8_t red = 0x3F;

    while(running){
        // Read 50 samples each with 2 ms in between (100 ms total)
        int avgValue = divider->value(50);
        // Convert the value to voltage at 3x gain and 5V reference
        float voltage = divider->computedValue(3, avgValue);
        string displayStr = to_string(voltage);
        displayStr = displayStr.substr(0, 4);

        // Write the battery voltage on the second line of the display
        crit.lock();
        lcd->setCursor(1, 0);
        lcd->write("Batt: " + displayStr + " V    ");
        crit.unlock();

        // Battery low, flash LCD and refresh more often
        if(voltage < 7.2f)
        {
            batteryLow = true;
            lcd->setColor(red, 0x00, 0x00);
            // Toggle red bits
            red = ~red;
            sleep(2);
        }
        else{
            // Battery was considered low but new reading is above threshold
            // Thus return to normal operation mode and make the LCD green
            if(batteryLow){
                lcd->setColor(0x00, 0xCF, 0x00);
            }
            batteryLow = false;
            // Refresh every 5 seconds
            sleep(5);
        }
    }
}

// IR sensors thread
void distanceIR(GroveMD *motors, RFR359F *fl, RFR359F *fr, RFR359F *rl, RFR359F *rr){
    while(running){
        // Set the corresponding sensor variable when an object is detected
        if(fl->objectDetected()){
            blockedFL = true;
        }
        else{
            blockedFL = false;
        }
        if(fr->objectDetected()){
            blockedFR = true;
        }
        else{
            blockedFR = false;
        }
        if(rl->objectDetected()){
            blockedRL = true;
        }
        else{
            blockedRL = false;
        }
        if(rr->objectDetected()){
            blockedRR = true;
        }
        else{
            blockedRR = false;
        }
        // Stop the motors if any sensor was triggered
        if(blockedFL || blockedFR || blockedRL || blockedRR){
            motors->setMotorSpeeds(0, 0);
        }
        // Refresh every 10 ms
        usleep(10000);
    }
}

int main(int argc, char **argv)
{
  // Register signal handler
  signal(SIGINT, signalHandler);

  // Instantiate an I2C Grove Motor Driver on default I2C bus
  // This will also set the I2C bus to 100 kHz for compatibility
  // Default address of 0x0f is used (all 4 switches in up position)
  GroveMD *motors = new GroveMD(GROVEMD_I2C_BUS, GROVEMD_DEFAULT_I2C_ADDR);
  if(motors == NULL){
      cerr << "Failed to initialize the motor driver." << endl;
      exit(EXIT_FAILURE);
  }

  // Initialize the Grove RGB Backlit LCD using implicit
  // 0x62 for RGB_ADDRESS and 0x3E for LCD_ADDRESS
  Jhd1313m1 *lcd = new upm::Jhd1313m1(0);
  if(lcd == NULL){
      cerr << "Failed to initialize the LCD." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate the HMC5883 compass on default I2C bus
  // The compass requires an I2C level translator to 3.3V if used
  Hmc5883l *compass = new Hmc5883l(0);
  if(compass == NULL){
      cerr << "Failed to initialize the HMC5883 compass." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate the Grove Voltage Divider on pin A0
  GroveVDiv *divider = new GroveVDiv(0);
  if(divider == NULL){
      cerr << "Failed to initialize the voltage divider." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate 4 Grove IR Distance Interrupters on pins D2, D4, D6, D8
  RFR359F *frontLeftIR = new RFR359F(2);
  RFR359F *frontRightIR = new RFR359F(4);
  RFR359F *rearLeftIR = new RFR359F(6);
  RFR359F *rearRightIR = new RFR359F(8);

  if(frontLeftIR == NULL || frontRightIR == NULL || rearLeftIR == NULL || rearRightIR == NULL){
      cerr << "Failed to initialize one of the IR sensors." << endl;
      exit(EXIT_FAILURE);
  }

  // Start independent threads for the different components
  // If you're not using a component comment out the corresponding thread call
  thread comp (displayHeading, lcd, compass);
  thread batt (displayBattery, lcd, divider);
  thread collision (distanceIR, motors, frontLeftIR, frontRightIR, rearLeftIR, rearRightIR);

  // Main event and control loop
  // Commands are given through stdin as tuples of the form <CMD_NAME SPEED>
  // Except for the <stop> command and are case sensitive
  while(running){

      string command;
      int speed;

      // Wait command from stdin
      cin.clear();
      cin >> command;
      if(command == "stop" || command.empty()){
          // Stop rover
          motors->setMotorSpeeds(0, 0);
          cout << "Rover stopping!" << endl;
          continue;
      }
      // Read speed
      cin >> speed;
      // Check against non-numbers entered in string
      if(cin.fail()){
          cerr << "Error: Bad input! Please check your command and try again." << endl;
          continue;
      }
      // Check for proper range
      if(speed < 0 || speed > 255){
          cerr << "Error: Speed needs to be between 0 to 255." << endl;
          continue;
      }
      // Direction is set based on command/keyword
      if(command == "fwd" && (!blockedFL || !blockedFR)){
          motors->setMotorDirections(GroveMD::DIR_CCW, GroveMD::DIR_CW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover going forward at speed " << speed << endl;
      }
      else if(command == "left"  && (!blockedFL || !blockedRL)){
          motors->setMotorDirections(GroveMD::DIR_CCW, GroveMD::DIR_CCW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover turning left at speed " << speed << endl;
      }
      else if(command == "right" && (!blockedFR || !blockedRR)){
          motors->setMotorDirections(GroveMD::DIR_CW, GroveMD::DIR_CW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover turning right at speed " << speed << endl;
      }
      else if(command == "rev"  && (!blockedRL || !blockedRR)){
          motors->setMotorDirections(GroveMD::DIR_CW, GroveMD::DIR_CCW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover in reverse at speed " << speed << endl;
      }
      else{
          motors->setMotorSpeeds(0, 0);
          cout << "Command not supported or direction blocked!" << endl;
      }
  }

  // Wait for threads to join back
  // If you're not using a component comment out the corresponding join call
  comp.join();
  batt.join();
  collision.join();

  cout << "Exiting..." << endl;

  // Clean up and exit
  delete lcd;
  delete compass;
  delete divider;
  delete motors;
  return 0;
}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2015, Arrayfire
 * all rights reserved.
 *
 * This file is distributed under 3-clause bsd license.
 * the complete license agreement can be obtained at:
 * http://Arrayfire.com/licenses/bsd-3-clause
 ********************************************************/

#include <af/features.h>
#include <Array.hpp>
#include <cmath>
#include <math.hpp>

using af::features;

namespace cpu
{

template<typename T>
void susan_responses(T* resp_out, const T* in,
                     const unsigned idim0, const unsigned idim1,
                     const int radius, const float t, const float g,
                     const unsigned border_len)
{
    const unsigned r = border_len;
    const int rSqrd = radius*radius;

    for (unsigned y = r; y < idim1 - r; ++y) {
        for (unsigned x = r; x < idim0 - r; ++x) {
            const unsigned idx = y * idim0 + x;
            T m_0 = in[idx];
            float nM = 0.0f;

            for (int i=-radius; i<=radius; ++i) {
                for (int j=-radius; j<=radius; ++j) {
                    if (i*i + j*j < rSqrd) {
                        int p = x + i;
                        int q = y + j;
                        T m = in[p + idim0 * q];
                        float exp_pow = std::pow((m - m_0)/t, 6.0);
                        float cM = std::exp(-exp_pow);
                        nM += cM;
                    }
                }
            }

            resp_out[idx] = nM < g ? g - nM : T(0);
        }
    }
}

template<typename T>
void non_maximal(float* x_out, float* y_out, float* resp_out,
                 unsigned* count, const unsigned idim0, const unsigned idim1,
                 const T* resp_in, const unsigned border_len, const unsigned max_corners)
{
    // Responses on the border don't have 8-neighbors to compare, discard them
    const unsigned r = border_len + 1;

    for (unsigned y = r; y < idim1 - r; y++) {
        for (unsigned x = r; x < idim0 - r; x++) {
            const T v = resp_in[y * idim0 + x];

            // Find maximum neighborhood response
            T max_v;
            max_v = max(resp_in[(y-1) * idim0 + x-1], resp_in[y * idim0 + x-1]);
            max_v = max(max_v, resp_in[(y+1) * idim0 + x-1]);
            max_v = max(max_v, resp_in[(y-1) * idim0 + x  ]);
            max_v = max(max_v, resp_in[(y+1) * idim0 + x  ]);
            max_v = max(max_v, resp_in[(y-1) * idim0 + x+1]);
            max_v = max(max_v, resp_in[(y)   * idim0 + x+1]);
            max_v = max(max_v, resp_in[(y+1) * idim0 + x+1]);

            // Stores corner to {x,y,resp}_out if it's response is maximum compared
            // to its 8-neighborhood and greater or equal minimum response
            if (v > max_v) {
                const unsigned idx = *count;
                *count += 1;
                if (idx < max_corners) {
                    x_out[idx]    = (float)x;
                    y_out[idx]    = (float)y;
                    resp_out[idx] = (float)v;
                }
            }
        }
    }
}

template<typename T>
unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out,
               const Array<T> &in,
               const unsigned radius, const float diff_thr, const float geom_thr,
               const float feature_ratio, const unsigned edge)
{
    dim4 idims = in.dims();

    const unsigned corner_lim = in.elements() * feature_ratio;
    float* x_corners          = memAlloc<float>(corner_lim);
    float* y_corners          = memAlloc<float>(corner_lim);
    float* resp_corners       = memAlloc<float>(corner_lim);

    T* resp = memAlloc<T>(in.elements());
    unsigned corners_found = 0;

    susan_responses<T>(resp, in.get(), idims[0], idims[1], radius, diff_thr, geom_thr, edge);

    non_maximal<T>(x_corners, y_corners, resp_corners, &corners_found,
                   idims[0], idims[1], resp, edge, corner_lim);

    memFree(resp);

    const unsigned corners_out = min(corners_found, corner_lim);
    if (corners_out == 0) {
        memFree(x_corners);
        memFree(y_corners);
        memFree(resp_corners);
        x_out    = createEmptyArray<float>(dim4());
        y_out    = createEmptyArray<float>(dim4());
        resp_out = createEmptyArray<float>(dim4());
        return 0;
    } else {

        x_out = createDeviceDataArray<float>(dim4(corners_out), (void*)x_corners);
        y_out = createDeviceDataArray<float>(dim4(corners_out), (void*)y_corners);
        resp_out = createDeviceDataArray<float>(dim4(corners_out), (void*)resp_corners);
        return corners_out;
    }
}

#define INSTANTIATE(T) \
template unsigned susan<T>(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,   \
                           const Array<T> &in, const unsigned radius, const float diff_thr,     \
                           const float geom_thr, const float feature_ratio, const unsigned edge);

INSTANTIATE(float )
INSTANTIATE(double)
INSTANTIATE(char  )
INSTANTIATE(int   )
INSTANTIATE(uint  )
INSTANTIATE(uchar )
INSTANTIATE(short)
INSTANTIATE(ushort)

}
<commit_msg>converted susan fn in cpu backend to asynchronous call<commit_after>/*******************************************************
 * Copyright (c) 2015, Arrayfire
 * all rights reserved.
 *
 * This file is distributed under 3-clause bsd license.
 * the complete license agreement can be obtained at:
 * http://Arrayfire.com/licenses/bsd-3-clause
 ********************************************************/

#include <af/features.h>
#include <Array.hpp>
#include <cmath>
#include <math.hpp>
#include <memory>
#include <platform.hpp>
#include <async_queue.hpp>

using af::features;
using std::shared_ptr;

namespace cpu
{

template<typename T>
void susan_responses(Array<T> output, const Array<T> input,
                     const unsigned idim0, const unsigned idim1,
                     const int radius, const float t, const float g,
                     const unsigned border_len)
{
    T* resp_out = output.get();
    const T* in = input.get();

    const unsigned r = border_len;
    const int rSqrd = radius*radius;

    for (unsigned y = r; y < idim1 - r; ++y) {
        for (unsigned x = r; x < idim0 - r; ++x) {
            const unsigned idx = y * idim0 + x;
            T m_0 = in[idx];
            float nM = 0.0f;

            for (int i=-radius; i<=radius; ++i) {
                for (int j=-radius; j<=radius; ++j) {
                    if (i*i + j*j < rSqrd) {
                        int p = x + i;
                        int q = y + j;
                        T m = in[p + idim0 * q];
                        float exp_pow = std::pow((m - m_0)/t, 6.0);
                        float cM = std::exp(-exp_pow);
                        nM += cM;
                    }
                }
            }

            resp_out[idx] = nM < g ? g - nM : T(0);
        }
    }
}

template<typename T>
void non_maximal(Array<float> xcoords, Array<float> ycoords, Array<float> response,
                 shared_ptr<unsigned> counter, const unsigned idim0, const unsigned idim1,
                 const Array<T> input, const unsigned border_len, const unsigned max_corners)
{
    float* x_out    = xcoords.get();
    float* y_out    = ycoords.get();
    float* resp_out = response.get();
    unsigned* count = counter.get();
    const T* resp_in= input.get();

    // Responses on the border don't have 8-neighbors to compare, discard them
    const unsigned r = border_len + 1;

    for (unsigned y = r; y < idim1 - r; y++) {
        for (unsigned x = r; x < idim0 - r; x++) {
            const T v = resp_in[y * idim0 + x];

            // Find maximum neighborhood response
            T max_v;
            max_v = max(resp_in[(y-1) * idim0 + x-1], resp_in[y * idim0 + x-1]);
            max_v = max(max_v, resp_in[(y+1) * idim0 + x-1]);
            max_v = max(max_v, resp_in[(y-1) * idim0 + x  ]);
            max_v = max(max_v, resp_in[(y+1) * idim0 + x  ]);
            max_v = max(max_v, resp_in[(y-1) * idim0 + x+1]);
            max_v = max(max_v, resp_in[(y)   * idim0 + x+1]);
            max_v = max(max_v, resp_in[(y+1) * idim0 + x+1]);

            // Stores corner to {x,y,resp}_out if it's response is maximum compared
            // to its 8-neighborhood and greater or equal minimum response
            if (v > max_v) {
                const unsigned idx = *count;
                *count += 1;
                if (idx < max_corners) {
                    x_out[idx]    = (float)x;
                    y_out[idx]    = (float)y;
                    resp_out[idx] = (float)v;
                }
            }
        }
    }
}

template<typename T>
unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out,
               const Array<T> &in,
               const unsigned radius, const float diff_thr, const float geom_thr,
               const float feature_ratio, const unsigned edge)
{
    dim4 idims = in.dims();
    const unsigned corner_lim = in.elements() * feature_ratio;

    auto x_corners    = createEmptyArray<float>(dim4(corner_lim));
    auto y_corners    = createEmptyArray<float>(dim4(corner_lim));
    auto resp_corners = createEmptyArray<float>(dim4(corner_lim));
    auto response     = createEmptyArray<T>(dim4(in.elements()));
    auto corners_found= std::shared_ptr<unsigned>(memAlloc<unsigned>(1), memFree<unsigned>);
    corners_found.get()[0] = 0;

    getQueue().enqueue(susan_responses<T>, response, in, idims[0], idims[1],
                       radius, diff_thr, geom_thr, edge);
    getQueue().enqueue(non_maximal<T>, x_corners, y_corners, resp_corners, corners_found,
                       idims[0], idims[1], response, edge, corner_lim);
    getQueue().sync();

    const unsigned corners_out = min((corners_found.get())[0], corner_lim);
    if (corners_out == 0) {
        x_out    = createEmptyArray<float>(dim4());
        y_out    = createEmptyArray<float>(dim4());
        resp_out = createEmptyArray<float>(dim4());
        return 0;
    } else {
        x_out = x_corners;
        y_out = y_corners;
        resp_out = resp_corners;
        x_out.resetDims(dim4(corners_out));
        y_out.resetDims(dim4(corners_out));
        resp_out.resetDims(dim4(corners_out));
        return corners_out;
    }
}

#define INSTANTIATE(T) \
template unsigned susan<T>(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,   \
                           const Array<T> &in, const unsigned radius, const float diff_thr,     \
                           const float geom_thr, const float feature_ratio, const unsigned edge);

INSTANTIATE(float )
INSTANTIATE(double)
INSTANTIATE(char  )
INSTANTIATE(int   )
INSTANTIATE(uint  )
INSTANTIATE(uchar )
INSTANTIATE(short)
INSTANTIATE(ushort)

}
<|endoftext|>


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

#ifndef MNIST_UTILS_HPP
#define MNIST_UTILS_HPP

#include <cmath>

namespace mnist {

template<typename Container>
void binarize_each(Container& values, double threshold = 30.0){
    for(auto& vec : values){
        for(auto& v : vec){
            v = v > threshold ? 1.0 : 0.0;
        }
    }
}

template<typename Container>
double mean(const Container& container){
    double mean = 0.0;
    for(auto& value : container){
        mean += value;
    }
    return mean / container.size();
}

template<typename Container>
double stddev(const Container& container, double mean){
    double std = 0.0;
    for(auto& value : container){
        std += (value - mean) * (value - mean);
    }
    return std::sqrt(std / container.size());
}

template<typename Container>
void normalize_each(Container& values){
    for(auto& vec : values){
        //zero-mean
        auto m = mnist::mean(vec);
        for(auto& v : vec){
            v -= m;
        }
        //unit variance
        auto s = stddev(vec, 0.0);
        for(auto& v : vec){
            v /= s;
        }
    }
}

template<typename Dataset>
void binarize_dataset(Dataset& dataset){
    binarize_each(dataset.training_images);
    binarize_each(dataset.test_images);
}

template<typename Dataset>
void normalize_dataset(Dataset& dataset){
    normalize_each(dataset.training_images);
    normalize_each(dataset.test_images);
}

};

#endif<commit_msg>Be pedantic<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef MNIST_UTILS_HPP
#define MNIST_UTILS_HPP

#include <cmath>

namespace mnist {

template<typename Container>
void binarize_each(Container& values, double threshold = 30.0){
    for(auto& vec : values){
        for(auto& v : vec){
            v = v > threshold ? 1.0 : 0.0;
        }
    }
}

template<typename Container>
double mean(const Container& container){
    double mean = 0.0;
    for(auto& value : container){
        mean += value;
    }
    return mean / container.size();
}

template<typename Container>
double stddev(const Container& container, double mean){
    double std = 0.0;
    for(auto& value : container){
        std += (value - mean) * (value - mean);
    }
    return std::sqrt(std / container.size());
}

template<typename Container>
void normalize_each(Container& values){
    for(auto& vec : values){
        //zero-mean
        auto m = mnist::mean(vec);
        for(auto& v : vec){
            v -= m;
        }
        //unit variance
        auto s = stddev(vec, 0.0);
        for(auto& v : vec){
            v /= s;
        }
    }
}

template<typename Dataset>
void binarize_dataset(Dataset& dataset){
    binarize_each(dataset.training_images);
    binarize_each(dataset.test_images);
}

template<typename Dataset>
void normalize_dataset(Dataset& dataset){
    normalize_each(dataset.training_images);
    normalize_each(dataset.test_images);
}

}

#endif
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief converter between integer and string

	@author MITSUNARI Shigeo(@herumi)
*/

#include <memory.h>
#include <limits>
#include <cybozu/exception.hpp>

namespace cybozu {

namespace atoi_local {

template<typename T, size_t n>
T convertToInt(bool *b, const char *p, size_t size, const char (&max)[n], T min, T overflow1, char overflow2)
{
	if (size > 0 && *p) {
		bool isMinus = false;
		size_t i = 0;
		if (*p == '-') {
			isMinus = true;
			i++;
		}
		if (i < size && p[i]) {
			// skip leading zero
			while (i < size && p[i] == '0') i++;
			// check minimum
			if (isMinus && size - i >= n - 1 && memcmp(max, &p[i], n - 1) == 0) {
				if (b) *b = true;
				return min;
			}
			T x = 0;
			for (;;) {
				unsigned char c;
				if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') {
					if (b) *b = true;
					return isMinus ? -x : x;
				}
				unsigned int y = c - '0';
				if (y > 9 || x > overflow1 || (x == overflow1 && c >= overflow2)) {
					break;
				}
				x = x * 10 + T(y);
				i++;
			}
		}
	}
	if (b) {
		*b = false;
		return 0;
	} else {
		throw cybozu::Exception("atoi::convertToInt") << cybozu::exception::makeString(p, size);
	}
}

template<typename T>
T convertToUint(bool *b, const char *p, size_t size, T overflow1, char overflow2)
{
	if (size > 0 && *p) {
		size_t i = 0;
		// skip leading zero
		while (i < size && p[i] == '0') i++;
		T x = 0;
		for (;;) {
			unsigned char c;
			if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') {
				if (b) *b = true;
				return x;
			}
			unsigned int y = c - '0';
			if (y > 9 || x > overflow1 || (x == overflow1 && c >= overflow2)) {
				break;
			}
			x = x * 10 + T(y);
			i++;
		}
	}
	if (b) {
		*b = false;
		return 0;
	} else {
		throw cybozu::Exception("atoi::convertToUint") << cybozu::exception::makeString(p, size);
	}
}

template<typename T>
T convertHexToInt(bool *b, const char *p, size_t size)
{
	if (size > 0 && *p) {
		size_t i = 0;
		T x = 0;
		for (;;) {
			unsigned int c;
			if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') {
				if (b) *b = true;
				return x;
			}
			if (c - 'A' <= 'F' - 'A') {
				c = (c - 'A') + 10;
			} else if (c - 'a' <= 'f' - 'a') {
				c = (c - 'a') + 10;
			} else if (c - '0' <= '9' - '0') {
				c = c - '0';
			} else {
				break;
			}
			// avoid overflow
			if (x > (std::numeric_limits<T>::max)() / 16) break;
			x = x * 16 + T(c);
			i++;
		}
	}
	if (b) {
		*b = false;
		return 0;
	} else {
		throw cybozu::Exception("atoi::convertHexToInt") << cybozu::exception::makeString(p, size);
	}
}

} // atoi_local

/**
	auto detect return value class
	@note if you set bool pointer p then throw nothing and set *p = false if bad string
*/
class atoi {
	const char *p_;
	size_t size_;
	bool *b_;
	void set(bool *b, const char *p, size_t size)
	{
		b_ = b;
		p_ = p;
		size_ = size;
	}
public:
	atoi(const char *p, size_t size = -1)
	{
		set(0, p, size);
	}
	atoi(bool *b, const char *p, size_t size = -1)
	{
		set(b, p, size);
	}
	atoi(const std::string& str)
	{
		set(0, str.c_str(), str.size());
	}
	atoi(bool *b, const std::string& str)
	{
		set(b, str.c_str(), str.size());
	}
	inline operator signed char() const
	{
		return atoi_local::convertToInt<signed char>(b_, p_, size_, "128", -128, 12, '8');
	}
	inline operator unsigned char() const
	{
		return atoi_local::convertToUint<unsigned char>(b_, p_, size_, 25, '6');
	}
	inline operator short() const
	{
		return atoi_local::convertToInt<short>(b_, p_, size_, "32768", -32768, 3276, '8');
	}
	inline operator unsigned short() const
	{
		return atoi_local::convertToUint<unsigned short>(b_, p_, size_, 6553, '6');
	}
	inline operator int() const
	{
		return atoi_local::convertToInt<int>(b_, p_, size_, "2147483648", /*INT_MIN*/-2147483648, 214748364, '8');
	}
	inline operator unsigned int() const
	{
		return atoi_local::convertToUint<unsigned int>(b_, p_, size_, 429496729, '6');
	}
	inline operator long long() const
	{
		return atoi_local::convertToInt<long long>(b_, p_, size_, "9223372036854775808", CYBOZU_LLONG_MIN, 922337203685477580LL, '8');
	}
	inline operator unsigned long long() const
	{
		return atoi_local::convertToUint<unsigned long long>(b_, p_, size_, 1844674407370955161ULL, '6');
	}
#if defined(__SIZEOF_LONG__) && (__SIZEOF_LONG__ == 8)
	inline operator long() const { return static_cast<long>(static_cast<long long>(*this)); }
	inline operator unsigned long() const { return static_cast<unsigned long>(static_cast<unsigned long long>(*this)); }
#else
	inline operator long() const { return static_cast<long>(static_cast<int>(*this)); }
	inline operator unsigned long() const { return static_cast<unsigned long>(static_cast<unsigned int>(*this)); }
#endif
};

class hextoi {
	const char *p_;
	size_t size_;
	bool *b_;
	void set(bool *b, const char *p, size_t size)
	{
		b_ = b;
		p_ = p;
		size_ = size;
	}
public:
	hextoi(const char *p, size_t size = -1)
	{
		set(0, p, size);
	}
	hextoi(bool *b, const char *p, size_t size = -1)
	{
		set(b, p, size);
	}
	hextoi(const std::string& str)
	{
		set(0, str.c_str(), str.size());
	}
	hextoi(bool *b, const std::string& str)
	{
		set(b, str.c_str(), str.size());
	}
	operator unsigned char() const { return atoi_local::convertHexToInt<unsigned char>(b_, p_, size_); }
	operator unsigned short() const { return atoi_local::convertHexToInt<unsigned short>(b_, p_, size_); }
	operator unsigned int() const { return atoi_local::convertHexToInt<unsigned int>(b_, p_, size_); }
	operator unsigned long() const { return atoi_local::convertHexToInt<unsigned long>(b_, p_, size_); }
	operator unsigned long long() const { return atoi_local::convertHexToInt<unsigned long long>(b_, p_, size_); }
	operator char() const { return atoi_local::convertHexToInt<char>(b_, p_, size_); }
	operator signed char() const { return atoi_local::convertHexToInt<signed char>(b_, p_, size_); }
	operator short() const { return atoi_local::convertHexToInt<short>(b_, p_, size_); }
	operator int() const { return atoi_local::convertHexToInt<int>(b_, p_, size_); }
	operator long() const { return atoi_local::convertHexToInt<long>(b_, p_, size_); }
	operator long long() const { return atoi_local::convertHexToInt<long long>(b_, p_, size_); }
};

} // cybozu
<commit_msg>avoid warning for vc<commit_after>#pragma once
/**
	@file
	@brief converter between integer and string

	@author MITSUNARI Shigeo(@herumi)
*/

#include <memory.h>
#include <limits>
#include <cybozu/exception.hpp>

namespace cybozu {

namespace atoi_local {

template<typename T, size_t n>
T convertToInt(bool *b, const char *p, size_t size, const char (&max)[n], T min, T overflow1, char overflow2)
{
	if (size > 0 && *p) {
		bool isMinus = false;
		size_t i = 0;
		if (*p == '-') {
			isMinus = true;
			i++;
		}
		if (i < size && p[i]) {
			// skip leading zero
			while (i < size && p[i] == '0') i++;
			// check minimum
			if (isMinus && size - i >= n - 1 && memcmp(max, &p[i], n - 1) == 0) {
				if (b) *b = true;
				return min;
			}
			T x = 0;
			for (;;) {
				unsigned char c;
				if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') {
					if (b) *b = true;
					return isMinus ? -x : x;
				}
				unsigned int y = c - '0';
				if (y > 9 || x > overflow1 || (x == overflow1 && c >= overflow2)) {
					break;
				}
				x = x * 10 + T(y);
				i++;
			}
		}
	}
	if (b) {
		*b = false;
		return 0;
	} else {
		throw cybozu::Exception("atoi::convertToInt") << cybozu::exception::makeString(p, size);
	}
}

template<typename T>
T convertToUint(bool *b, const char *p, size_t size, T overflow1, char overflow2)
{
	if (size > 0 && *p) {
		size_t i = 0;
		// skip leading zero
		while (i < size && p[i] == '0') i++;
		T x = 0;
		for (;;) {
			unsigned char c;
			if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') {
				if (b) *b = true;
				return x;
			}
			unsigned int y = c - '0';
			if (y > 9 || x > overflow1 || (x == overflow1 && c >= overflow2)) {
				break;
			}
			x = x * 10 + T(y);
			i++;
		}
	}
	if (b) {
		*b = false;
		return 0;
	} else {
		throw cybozu::Exception("atoi::convertToUint") << cybozu::exception::makeString(p, size);
	}
}

template<typename T>
T convertHexToInt(bool *b, const char *p, size_t size)
{
	if (size > 0 && *p) {
		size_t i = 0;
		T x = 0;
		for (;;) {
			unsigned int c;
			if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') {
				if (b) *b = true;
				return x;
			}
			if (c - 'A' <= 'F' - 'A') {
				c = (c - 'A') + 10;
			} else if (c - 'a' <= 'f' - 'a') {
				c = (c - 'a') + 10;
			} else if (c - '0' <= '9' - '0') {
				c = c - '0';
			} else {
				break;
			}
			// avoid overflow
			if (x > (std::numeric_limits<T>::max)() / 16) break;
			x = x * 16 + T(c);
			i++;
		}
	}
	if (b) {
		*b = false;
		return 0;
	} else {
		throw cybozu::Exception("atoi::convertHexToInt") << cybozu::exception::makeString(p, size);
	}
}

} // atoi_local

/**
	auto detect return value class
	@note if you set bool pointer p then throw nothing and set *p = false if bad string
*/
class atoi {
	const char *p_;
	size_t size_;
	bool *b_;
	void set(bool *b, const char *p, size_t size)
	{
		b_ = b;
		p_ = p;
		size_ = size;
	}
public:
	atoi(const char *p, size_t size = -1)
	{
		set(0, p, size);
	}
	atoi(bool *b, const char *p, size_t size = -1)
	{
		set(b, p, size);
	}
	atoi(const std::string& str)
	{
		set(0, str.c_str(), str.size());
	}
	atoi(bool *b, const std::string& str)
	{
		set(b, str.c_str(), str.size());
	}
	inline operator signed char() const
	{
		return atoi_local::convertToInt<signed char>(b_, p_, size_, "128", -128, 12, '8');
	}
	inline operator unsigned char() const
	{
		return atoi_local::convertToUint<unsigned char>(b_, p_, size_, 25, '6');
	}
	inline operator short() const
	{
		return atoi_local::convertToInt<short>(b_, p_, size_, "32768", -32768, 3276, '8');
	}
	inline operator unsigned short() const
	{
		return atoi_local::convertToUint<unsigned short>(b_, p_, size_, 6553, '6');
	}
	inline operator int() const
	{
		return atoi_local::convertToInt<int>(b_, p_, size_, "2147483648", (std::numeric_limits<int>::min)() /* -2147483648 */, 214748364, '8');
	}
	inline operator unsigned int() const
	{
		return atoi_local::convertToUint<unsigned int>(b_, p_, size_, 429496729, '6');
	}
	inline operator long long() const
	{
		return atoi_local::convertToInt<long long>(b_, p_, size_, "9223372036854775808", CYBOZU_LLONG_MIN, 922337203685477580LL, '8');
	}
	inline operator unsigned long long() const
	{
		return atoi_local::convertToUint<unsigned long long>(b_, p_, size_, 1844674407370955161ULL, '6');
	}
#if defined(__SIZEOF_LONG__) && (__SIZEOF_LONG__ == 8)
	inline operator long() const { return static_cast<long>(static_cast<long long>(*this)); }
	inline operator unsigned long() const { return static_cast<unsigned long>(static_cast<unsigned long long>(*this)); }
#else
	inline operator long() const { return static_cast<long>(static_cast<int>(*this)); }
	inline operator unsigned long() const { return static_cast<unsigned long>(static_cast<unsigned int>(*this)); }
#endif
};

class hextoi {
	const char *p_;
	size_t size_;
	bool *b_;
	void set(bool *b, const char *p, size_t size)
	{
		b_ = b;
		p_ = p;
		size_ = size;
	}
public:
	hextoi(const char *p, size_t size = -1)
	{
		set(0, p, size);
	}
	hextoi(bool *b, const char *p, size_t size = -1)
	{
		set(b, p, size);
	}
	hextoi(const std::string& str)
	{
		set(0, str.c_str(), str.size());
	}
	hextoi(bool *b, const std::string& str)
	{
		set(b, str.c_str(), str.size());
	}
	operator unsigned char() const { return atoi_local::convertHexToInt<unsigned char>(b_, p_, size_); }
	operator unsigned short() const { return atoi_local::convertHexToInt<unsigned short>(b_, p_, size_); }
	operator unsigned int() const { return atoi_local::convertHexToInt<unsigned int>(b_, p_, size_); }
	operator unsigned long() const { return atoi_local::convertHexToInt<unsigned long>(b_, p_, size_); }
	operator unsigned long long() const { return atoi_local::convertHexToInt<unsigned long long>(b_, p_, size_); }
	operator char() const { return atoi_local::convertHexToInt<char>(b_, p_, size_); }
	operator signed char() const { return atoi_local::convertHexToInt<signed char>(b_, p_, size_); }
	operator short() const { return atoi_local::convertHexToInt<short>(b_, p_, size_); }
	operator int() const { return atoi_local::convertHexToInt<int>(b_, p_, size_); }
	operator long() const { return atoi_local::convertHexToInt<long>(b_, p_, size_); }
	operator long long() const { return atoi_local::convertHexToInt<long long>(b_, p_, size_); }
};

} // cybozu
<|endoftext|>