<commit_before>//
// Created by per-arne on 02.04.17.
//

#include <fstream>
#include <iostream>
#include "ResourceLoader.h"
#include "../../../include/rapidjson/include/rapidjson/istreamwrapper.h"
#include <stdio.h>

#include <stdio.h>
#include <string>
#ifdef _WIN32
#include <direct.h>
#define GetCurrentDir _getcwd
#elif __linux__
#include <unistd.h>
#define GetCurrentDir getcwd
#endif

std::string GetCurrentWorkingDir()
{
    char buff[FILENAME_MAX];
    GetCurrentDir(buff, FILENAME_MAX);
    std::string current_working_dir(buff);
    return current_working_dir;
}

void ResourceLoader::loadMapJSON(std::string map_file) {

    if(mapLoaded) return;
	std::string filePath = GetCurrentWorkingDir() + "/data/maps/" + map_file;

    // Read Map data
    std::ifstream map(filePath);

	if (map.is_open()) {
		rapidjson::IStreamWrapper isw(map);
		rapidjson::Document d;
		mapJSON.ParseStream(isw);
		mapLoaded = true;
		if(mapJSON.IsNull()){
			throw std::runtime_error("File Error: Could not find: " + map_file + " (" + filePath + ").\nEnsure that the data directory exists!");
		}
	}
	else {
		throw std::runtime_error("File Error: Could not find: " + map_file + " (" + filePath + ").\nEnsure that the data directory exists!");
	}

}

void ResourceLoader::loadTileJSON() {
	std::string fileName = "tile_properties.json";
	std::string filePath = GetCurrentWorkingDir() + "/data/" + fileName;

    std::ifstream map(filePath);
	if (map.is_open()) {
		rapidjson::IStreamWrapper isw(map);
		tileJSON.ParseStream(isw);
		return;
	}
	throw std::runtime_error("File Error: Could not find: " + fileName + "(" + filePath + ").\nEnsure that the data directory exists!");

}

<commit_msg>* Fixed data paths for assets in C++<commit_after>//
// Created by per-arne on 02.04.17.
//

#include <fstream>
#include <iostream>
#include "ResourceLoader.h"
#include "../../../include/rapidjson/include/rapidjson/istreamwrapper.h"
#include <stdio.h>

#include <stdio.h>
#include <string>
#ifdef _WIN32
#include <direct.h>
#define GetCurrentDir _getcwd
#elif __linux__
#include <unistd.h>
#define GetCurrentDir getcwd
#endif

std::string GetCurrentWorkingDir()
{
    char buff[FILENAME_MAX];
    GetCurrentDir(buff, FILENAME_MAX);
    std::string current_working_dir(buff);
    return current_working_dir;
}

void ResourceLoader::loadMapJSON(std::string map_file) {

    if(mapLoaded) return;
	std::string filePath = GetCurrentWorkingDir() + "/assets/maps/" + map_file;

    // Read Map data
    std::ifstream map(filePath);

	if (map.is_open()) {
		rapidjson::IStreamWrapper isw(map);
		rapidjson::Document d;
		mapJSON.ParseStream(isw);
		mapLoaded = true;
		if(mapJSON.IsNull()){
			throw std::runtime_error("File Error: Could not find: " + map_file + " (" + filePath + ").\nEnsure that the data directory exists!");
		}
	}
	else {
		throw std::runtime_error("File Error: Could not find: " + map_file + " (" + filePath + ").\nEnsure that the data directory exists!");
	}

}

void ResourceLoader::loadTileJSON() {
	std::string fileName = "tile_properties.json";
	std::string filePath = GetCurrentWorkingDir() + "/assets/" + fileName;

    std::ifstream map(filePath);
	if (map.is_open()) {
		rapidjson::IStreamWrapper isw(map);
		tileJSON.ParseStream(isw);
		return;
	}
	throw std::runtime_error("File Error: Could not find: " + fileName + "(" + filePath + ").\nEnsure that the data directory exists!");

}

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *       [ Caolán McNamara <caolanm:redhat.com> ]
 * Portions created by Caolán McNamara are Copyright (C) 2010 * Red Hat, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): Caolán McNamara <caolanm@redhat.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */
#include <sal/main.h>
#include <rtl/ustring.hxx>
#include <osl/time.h>
#include <osl/process.h>

#include <iostream>
#include <sstream>
#include <fstream>

#ifdef HAVE_CALLGRIND
#    include <valgrind/callgrind.h>
int COUNT = 1;
#else
#    define CALLGRIND_DUMP_STATS_AT
#    define CALLGRIND_START_INSTRUMENTATION
#    define CALLGRIND_STOP_INSTRUMENTATION
#    define CALLGRIND_ZERO_STATS
int COUNT = 10000000;
#endif

#if defined __GXX_EXPERIMENTAL_CXX0X__
#   define HAVE_CXX_Ox 1
#endif

#ifdef HAVE_CXX_Ox
#  define SAL_DECLARE_UTF16(str) u ## str
#elif (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x550)
#  define SAL_DECLARE_UTF16(str) U ## str
#elif __SIZEOF_WCHAR_T__ == 2
#  define SAL_DECLARE_UTF16(str) L ## str
#endif

#ifdef SAL_DECLARE_UTF16
#  define RTL_CONSTASCII_USTRINGPARAM_WIDE(str) \
     reinterpret_cast<const sal_Unicode*>(SAL_DECLARE_UTF16(str)), (SAL_N_ELEMENTS(str)-1)
#endif

#define RTL_CONSTASCII_USTRINGPARAM_CLASSIC(str) \
    str, ((sal_Int32)(SAL_N_ELEMENTS(str)-1)), RTL_TEXTENCODING_ASCII_US

int currenttest = 1;
oslProcessInfo pidinfo;

class TimerMeasure
{
private:
    const char *m_pMessage;
    sal_uInt32 m_nStartTime, m_nEndTime;
public:
    TimerMeasure(const char *pMessage)
    : m_pMessage(pMessage)
    {
        m_nStartTime = osl_getGlobalTimer();
        CALLGRIND_START_INSTRUMENTATION
        CALLGRIND_ZERO_STATS
    }

    ~TimerMeasure()
    {
        CALLGRIND_STOP_INSTRUMENTATION
        CALLGRIND_DUMP_STATS_AT(m_pMessage);
        m_nEndTime = osl_getGlobalTimer();
        std::cout << m_pMessage << std::endl;
        std::cout << "    callgrind Instruction cost is: " << std::flush;

        std::stringstream aFileName;
        aFileName << "callgrind.out." << pidinfo.Ident << "." << currenttest;

        std::ifstream myfile(aFileName.str(), std::ios::in);
        if (myfile.is_open())
        {
            std::stringstream aGetGrindStats;
            aGetGrindStats << "callgrind_annotate " << aFileName.str() <<
                " | grep TOTALS | sed 's/ PROGRAM TOTALS//'";
            system(aGetGrindStats.str().c_str());
            myfile.close();
        }
        else
            std::cout << "Unavailable" << std::endl;
        currenttest++;
#ifndef HAVE_CALLGRIND
        std::cout << "    Elapsed Time is: " << m_nEndTime - m_nStartTime << "ms" << std::endl;
#endif
    }
};

#define TIME(msg, test) \
{\
    { test } /*Run the test one to shake out any firsttime lazy loading stuff*/ \
    TimerMeasure aMeasure(msg);\
    for (int i = 0; i < COUNT; ++i)\
        test\
}

SAL_IMPLEMENT_MAIN()
{
    CALLGRIND_STOP_INSTRUMENTATION
    CALLGRIND_ZERO_STATS

    pidinfo.Size = sizeof(pidinfo);
    osl_getProcessInfo(0, osl_Process_IDENTIFIER, &pidinfo);

#ifdef HAVE_CALLGRIND
    std::cout << "Execute using: valgrind --tool=callgrind ./measure_oustrings" << std::endl;
#else
    //get my cpu fan up to speed :-)
    for (int i = 0; i < 10000000; ++i)
    {
        rtl::OUString sFoo(rtl::OUString::createFromAscii("X"));
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_CLASSIC("X"));
        rtl::OUString sBaz(static_cast<sal_Unicode>('X'));
        rtl::OUString sNone;
    }
#endif

    std::cout << "--Empty Strings--" << std::endl;

    TIME
    (
        "rtl::OUString()",
        rtl::OUString sFoo;
    )

    TIME
    (
        "rtl::OUString::createFromAscii()",
        rtl::OUString sFoo(rtl::OUString::createFromAscii(""));
    )

    std::cout << "--Single Chars--" << std::endl;

    TIME
    (
        "rtl::OUString(static_cast<sal_Unicode>('X')",
        rtl::OUString sBaz(static_cast<sal_Unicode>('X'));
    )

#ifdef SAL_DECLARE_UTF16
    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_WIDE(\"X\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_WIDE("X"));
    )
#endif

    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_CLASSIC(\"X\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_CLASSIC("X"));
    )

    TIME
    (
        "rtl::OUString::createFromAscii(\"X\")",
        rtl::OUString sFoo(rtl::OUString::createFromAscii("X"));
    )

    std::cout << "--MultiChar Strings--" << std::endl;

#ifdef SAL_DECLARE_UTF16
    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_WIDE(\"XXXXXXXX\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_WIDE("XXXXXXXXXXXXXXX"));
    )
#endif

    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_CLASSIC(\"XXXXXXXX\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_CLASSIC("XXXXXXXXXXXXXXX"));
    )

    TIME
    (
        "rtl::OUString::createFromAscii(\"XXXXXXXX\")",
        rtl::OUString sFoo(rtl::OUString::createFromAscii("XXXXXXXXXXXXXXX"));
    )

    return 0;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>add performance comparison test for equalsAscii group<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *       [ Caolán McNamara <caolanm:redhat.com> ]
 * Portions created by Caolán McNamara are Copyright (C) 2010 * Red Hat, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): Caolán McNamara <caolanm@redhat.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */
#include <sal/main.h>
#include <rtl/ustring.hxx>
#include <osl/time.h>
#include <osl/process.h>

#include <iostream>
#include <sstream>
#include <fstream>

#ifdef HAVE_CALLGRIND
#    include <valgrind/callgrind.h>
int COUNT = 1;
#else
#    define CALLGRIND_DUMP_STATS_AT
#    define CALLGRIND_START_INSTRUMENTATION
#    define CALLGRIND_STOP_INSTRUMENTATION
#    define CALLGRIND_ZERO_STATS
int COUNT = 10000000;
#endif

#if defined __GXX_EXPERIMENTAL_CXX0X__
#   define HAVE_CXX_Ox 1
#endif

#ifdef HAVE_CXX_Ox
#  define SAL_DECLARE_UTF16(str) u ## str
#elif (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x550)
#  define SAL_DECLARE_UTF16(str) U ## str
#elif __SIZEOF_WCHAR_T__ == 2
#  define SAL_DECLARE_UTF16(str) L ## str
#endif

#ifdef SAL_DECLARE_UTF16
#  define RTL_CONSTASCII_USTRINGPARAM_WIDE(str) \
     reinterpret_cast<const sal_Unicode*>(SAL_DECLARE_UTF16(str)), (SAL_N_ELEMENTS(str)-1)
#endif

#define RTL_CONSTASCII_USTRINGPARAM_CLASSIC(str) \
    str, ((sal_Int32)(SAL_N_ELEMENTS(str)-1)), RTL_TEXTENCODING_ASCII_US

int currenttest = 1;
oslProcessInfo pidinfo;

class TimerMeasure
{
private:
    const char *m_pMessage;
    sal_uInt32 m_nStartTime, m_nEndTime;
public:
    TimerMeasure(const char *pMessage)
    : m_pMessage(pMessage)
    {
        m_nStartTime = osl_getGlobalTimer();
        CALLGRIND_START_INSTRUMENTATION
        CALLGRIND_ZERO_STATS
    }

    ~TimerMeasure()
    {
        CALLGRIND_STOP_INSTRUMENTATION
        CALLGRIND_DUMP_STATS_AT(m_pMessage);
        m_nEndTime = osl_getGlobalTimer();
        std::cout << m_pMessage << std::endl;
        std::cout << "    callgrind Instruction cost is: " << std::flush;

        std::stringstream aFileName;
        aFileName << "callgrind.out." << pidinfo.Ident << "." << currenttest;

        std::ifstream myfile(aFileName.str(), std::ios::in);
        if (myfile.is_open())
        {
            std::stringstream aGetGrindStats;
            aGetGrindStats << "callgrind_annotate " << aFileName.str() <<
                " | grep TOTALS | sed 's/ PROGRAM TOTALS//'";
            system(aGetGrindStats.str().c_str());
            myfile.close();
        }
        else
            std::cout << "Unavailable" << std::endl;
        currenttest++;
#ifndef HAVE_CALLGRIND
        std::cout << "    Elapsed Time is: " << m_nEndTime - m_nStartTime << "ms" << std::endl;
#endif
    }
};

#define TIME(msg, test) \
{\
    { test } /*Run the test one to shake out any firsttime lazy loading stuff*/ \
    TimerMeasure aMeasure(msg);\
    for (int i = 0; i < COUNT; ++i)\
        test\
}

SAL_IMPLEMENT_MAIN()
{
    CALLGRIND_STOP_INSTRUMENTATION
    CALLGRIND_ZERO_STATS

    pidinfo.Size = sizeof(pidinfo);
    osl_getProcessInfo(0, osl_Process_IDENTIFIER, &pidinfo);

#ifdef HAVE_CALLGRIND
    std::cout << "Execute using: valgrind --tool=callgrind ./measure_oustrings" << std::endl;
#else
    //get my cpu fan up to speed :-)
    for (int i = 0; i < 10000000; ++i)
    {
        rtl::OUString sFoo(rtl::OUString::createFromAscii("X"));
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_CLASSIC("X"));
        rtl::OUString sBaz(static_cast<sal_Unicode>('X'));
        rtl::OUString sNone;
    }
#endif

    std::cout << "--Empty Strings Construction--" << std::endl;

    TIME
    (
        "rtl::OUString()",
        rtl::OUString sFoo;
    )

    TIME
    (
        "rtl::OUString::createFromAscii()",
        rtl::OUString sFoo(rtl::OUString::createFromAscii(""));
    )

    std::cout << "--Single Chars Construction--" << std::endl;

    TIME
    (
        "rtl::OUString(static_cast<sal_Unicode>('X')",
        rtl::OUString sBaz(static_cast<sal_Unicode>('X'));
    )

#ifdef SAL_DECLARE_UTF16
    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_WIDE(\"X\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_WIDE("X"));
    )
#endif

    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_CLASSIC(\"X\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_CLASSIC("X"));
    )

    TIME
    (
        "rtl::OUString::createFromAscii(\"X\")",
        rtl::OUString sFoo(rtl::OUString::createFromAscii("X"));
    )

    std::cout << "--MultiChar Strings Construction--" << std::endl;

#ifdef SAL_DECLARE_UTF16
    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_WIDE(\"XXXXXXXX\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_WIDE("XXXXXXXXXXXXXXX"));
    )
#endif

    TIME
    (
        "rtl::OUString(RTL_CONSTASCII_USTRINGPARAM_CLASSIC(\"XXXXXXXX\"))",
        rtl::OUString sBar(RTL_CONSTASCII_USTRINGPARAM_CLASSIC("XXXXXXXXXXXXXXX"));
    )

    TIME
    (
        "rtl::OUString::createFromAscii(\"XXXXXXXX\")",
        rtl::OUString sFoo(rtl::OUString::createFromAscii("XXXXXXXXXXXXXXX"));
    )

    std::cout << "--Ascii String Comparison--" << std::endl;

    rtl::OUString sCompare(RTL_CONSTASCII_USTRINGPARAM_CLASSIC("XXXXXXXXXXXXXXX"));

    TIME
    (
        "rtl::OUString::equalsAsciiL (false)",
        sCompare.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("apple"));
    )

    TIME
    (
        "rtl::OUString::equalsAscii (false)",
        sCompare.equalsAscii("apple");
    )

    TIME
    (
        "rtl::OUString::equalsAsciiL(true)",
        sCompare.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("XXXXXXXXXXXXXXX"));
    )

    TIME
    (
        "rtl::OUString::equalsAscii (true)",
        sCompare.equalsAscii("XXXXXXXXXXXXXXX");
    )

    return 0;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "CheckEmptyTransactionTransformer.h"

#include "ASTNodeEraser.h"
#include "cling/Interpreter/Transaction.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Sema/Sema.h"

#include <algorithm>

using namespace clang;

namespace cling {
  void CheckEmptyTransactionTransformer::Transform() {
    Transaction* T = getTransaction();
    if (FunctionDecl* FD = T->getWrapperFD()) {
      CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
      if (!CS->size() || (CS->size() == 1 && isa<NullStmt>(CS->body_back()))) {
        // This is an empty wrapper function. Get rid of it.
        DeclGroupRef DGR(FD);
        Transaction::DelayCallInfo DCI (DGR,
                                        Transaction::kCCIHandleTopLevelDecl);
        Transaction::iterator found
          = std::find(T->decls_begin(), T->decls_end(), DCI);
        if (found != T->decls_end()) {
          T->erase(found);
        }
        cling::Transaction T(m_Sema->getASTContext());
        T.append(FD);
        ASTNodeEraser eraser(m_Sema, /*ExecutionEngine*/0);
        eraser.RevertTransaction(&T);
      }
    }
  }
} // end namespace cling
<commit_msg>Clarification comment.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "CheckEmptyTransactionTransformer.h"

#include "ASTNodeEraser.h"
#include "cling/Interpreter/Transaction.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Sema/Sema.h"

#include <algorithm>

using namespace clang;

namespace cling {
  void CheckEmptyTransactionTransformer::Transform() {
    Transaction* T = getTransaction();
    if (FunctionDecl* FD = T->getWrapperFD()) {
      CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
      if (!CS->size() || (CS->size() == 1 && isa<NullStmt>(CS->body_back()))) {
        // This is an empty wrapper function. Get rid of it.
        DeclGroupRef DGR(FD);
        Transaction::DelayCallInfo DCI (DGR,
                                        Transaction::kCCIHandleTopLevelDecl);
        Transaction::iterator found
          = std::find(T->decls_begin(), T->decls_end(), DCI);
        if (found != T->decls_end()) {
          T->erase(found);
        }
        cling::Transaction T(m_Sema->getASTContext());
        T.append(FD);
        // We know that it didn't end up in the EE by design.
        ASTNodeEraser eraser(m_Sema, /*ExecutionEngine*/0);
        eraser.RevertTransaction(&T);
      }
    }
  }
} // end namespace cling
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    <algorithm>
#include    <cstdlib>

#include    "../../Foundation/Characters/Tokenize.h"
#include    "../../Foundation/Containers/Common.h"
#include    "../../Foundation/DataExchange/BadFormatException.h"
#include    "../../Foundation/Debug/Assertions.h"
#include    "../../Foundation/Execution/Exceptions.h"
#include    "../../Foundation/Execution/Thread.h"
#include    "../../Foundation/Memory/SmallStackBuffer.h"

#include    "Listener.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Memory;

using   namespace   Stroika::Frameworks;
using   namespace   Stroika::Frameworks::WebServer;

struct Listener::Rep_ {
    Rep_ (const SocketAddress& addr, const function<void (Socket newConnection)>& newConnectionAcceptor)
        : fSockAddr (addr)
        , fNewConnectionAcceptor (newConnectionAcceptor)
        , fMasterSocket ()
    {
        fMasterSocket.Bind (addr);  // do in CTOR so throw propagated
        fMasterSocket.Listen (10);//need param

        fListenThread = Execution::Thread ([this]() {
            while (true) {
                // unclear what todo with expcetions here
                // probnably ignore all but for theradabort.
                // may need virtual fucntions to handle? Or std::function passed in?
                Socket s = fMasterSocket.Accept ();
                fNewConnectionAcceptor (s);
            }
        });
        fListenThread.Start ();

    }
    ~Rep_ ()
    {
        // critical we wait for finish of thread cuz it has bare 'this' pointer captured
        IgnoreExceptionsForCall (fListenThread.AbortAndWaitForDone ());
    }

    SocketAddress fSockAddr;
    function<void (Socket newConnection)> fNewConnectionAcceptor;
    Socket  fMasterSocket;
    Execution::Thread fListenThread;
};

Listener::Listener (const SocketAddress& addr, const function<void (Socket newConnection)>& newConnectionAcceptor)
    : fRep_ (new Rep_ (addr, newConnectionAcceptor))
{
}
<commit_msg>WebServer Listener cleanups<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    <algorithm>
#include    <cstdlib>

#include    "../../Foundation/Characters/Tokenize.h"
#include    "../../Foundation/Containers/Common.h"
#include    "../../Foundation/DataExchange/BadFormatException.h"
#include    "../../Foundation/Debug/Assertions.h"
#include    "../../Foundation/Execution/Exceptions.h"
#include    "../../Foundation/Execution/Thread.h"
#include    "../../Foundation/Memory/SmallStackBuffer.h"

#include    "Listener.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Memory;

using   namespace   Stroika::Frameworks;
using   namespace   Stroika::Frameworks::WebServer;

struct Listener::Rep_ {
    Rep_ (const SocketAddress& addr, const function<void (Socket newConnection)>& newConnectionAcceptor)
        : fSockAddr (addr)
        , fNewConnectionAcceptor (newConnectionAcceptor)
        , fMasterSocket ()
    {
        fMasterSocket.Bind (addr);  // do in CTOR so throw propagated
        fMasterSocket.Listen (10);//need param

        fListenThread = Execution::Thread ([this]() {
            while (true) {
                // unclear what todo with expcetions here
                // probnably ignore all but for theradabort.
                // may need virtual fucntions to handle? Or std::function passed in?
                Socket s = fMasterSocket.Accept ();
                fNewConnectionAcceptor (s);
            }
        });
        fListenThread.SetThreadName (L"WebServer Listener");    // @todo include sockaddr 'pretty print' in name?
        fListenThread.Start ();

    }
    ~Rep_ ()
    {
        // critical we wait for finish of thread cuz it has bare 'this' pointer captured
        IgnoreExceptionsForCall (fListenThread.AbortAndWaitForDone ());
    }

    SocketAddress fSockAddr;
    function<void (Socket newConnection)> fNewConnectionAcceptor;
    Socket  fMasterSocket;
    Execution::Thread fListenThread;
};

Listener::Listener (const SocketAddress& addr, const function<void (Socket newConnection)>& newConnectionAcceptor)
    : fRep_ (new Rep_ (addr, newConnectionAcceptor))
{
}
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2020 Simon Sandström
 *
 * 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 "wsworld.h"

#include "logger.h"

namespace wsclient::wsworld
{

void Map::setFullMapData(const protocol::client::FullMap& map_data)
{
  // Full map data is width=18, height=14
  m_tiles.setMapPosition(map_data.position);
  auto it = map_data.tiles.begin();
  for (auto x = 0; x < consts::known_tiles_x; x++)
  {
    for (auto y = 0; y < consts::known_tiles_y; y++)
    {
      auto& tile = m_tiles.getTileLocalPos(x, y);
      setTile(*it, &tile);
      ++it;
    }
  }

  m_ready = true;
}

void Map::setPartialMapData(const protocol::client::PartialMap& map_data)
{
  // Set new map position
  const auto old_position = m_tiles.getMapPosition();
  const auto x_diff = map_data.direction == common::Direction::EAST ? 1 : (map_data.direction == common::Direction::WEST ? -1 : 0);
  const auto y_diff = map_data.direction == common::Direction::SOUTH ? 1 : (map_data.direction == common::Direction::NORTH ? -1 : 0);
  const auto new_position = common::Position(old_position.getX() + x_diff,
                                             old_position.getY() + y_diff,
                                             old_position.getZ());
  m_tiles.setMapPosition(new_position);
  LOG_INFO("%s: updated map position from %s to %s",
           __func__,
           old_position.toString().c_str(),
           new_position.toString().c_str());

  // Shift Tiles
  m_tiles.shiftTiles(map_data.direction);

  // Add new Tiles
  auto it = map_data.tiles.begin();
  switch (map_data.direction)
  {
    case common::Direction::NORTH:
      for (auto x = 0; x < consts::known_tiles_x; x++)
      {
        auto& tile = m_tiles.getTileLocalPos(x, 0);
        setTile(*it, &tile);
        ++it;
      }
      break;

    case common::Direction::EAST:
      for (auto y = 0; y < consts::known_tiles_y; y++)
      {
        auto& tile = m_tiles.getTileLocalPos(consts::known_tiles_x - 1, y);
        setTile(*it, &tile);
        ++it;
      }
      break;

    case common::Direction::SOUTH:
      for (auto x = 0; x < consts::known_tiles_x; x++)
      {
        auto& tile = m_tiles.getTileLocalPos(x, consts::known_tiles_y - 1);
        setTile(*it, &tile);
        ++it;
      }
      break;

    case common::Direction::WEST:
      for (auto y = 0; y < consts::known_tiles_y; y++)
      {
        auto& tile = m_tiles.getTileLocalPos(0, y);
        setTile(*it, &tile);
        ++it;
      }
      break;
  }
}

void Map::addCreature(const common::Position& position, common::CreatureId creature_id)
{
  addThing(position, creature_id);
}

void Map::addCreature(const common::Position& position, const protocol::Creature& creature)
{
  // TODO: add to known creatures if needed?
  addCreature(position, creature.id);
}

void Map::addItem(const common::Position& position,
                  common::ItemTypeId item_type_id,
                  std::uint8_t extra,
                  bool onTop)
{
  // TODO: why is onTop sent here?
  (void)onTop;

  Item item;
  item.type = &((*m_itemtypes)[item_type_id]);
  item.extra = extra;
  addThing(position, item);
}

void Map::removeThing(const common::Position& position, std::uint8_t stackpos)
{
  const auto pre = m_tiles.getTile(position).things.size();
  auto& things = m_tiles.getTile(position).things;
  things.erase(things.cbegin() + stackpos);
  const auto post = m_tiles.getTile(position).things.size();

  LOG_INFO("%s: removed thing from position=%s stackpos=%d (size=%d->%d)",
           __func__,
           position.toString().c_str(),
           stackpos,
           pre,
           post);
}

void Map::moveThing(const common::Position& from_position,
                    std::uint8_t from_stackpos,
                    const common::Position& to_position)
{
  const auto thing = getThing(from_position, from_stackpos);
  removeThing(from_position, from_stackpos);
  addThing(to_position, thing);
}

const Tile& Map::getTile(const common::Position& position) const
{
  return m_tiles.getTile(position);
}

const Creature* Map::getCreature(common::CreatureId creature_id) const
{
  auto it = std::find_if(m_known_creatures.cbegin(),
                         m_known_creatures.cend(),
                         [creature_id](const Creature& creature)
  {
    return creature_id == creature.id;
  });
  if (it == m_known_creatures.cend())
  {
    return nullptr;
  }
  return &(*it);
}

void Map::setTile(const protocol::Tile& protocol_tile, Tile* world_tile)
{
  world_tile->things.clear();
  if (protocol_tile.skip)
  {
    return;
  }

  for (const auto& thing : protocol_tile.things)
  {
    if (std::holds_alternative<protocol::Creature>(thing))
    {
      const auto& creature = std::get<protocol::Creature>(thing);
      if (creature.known)
      {
        // Update known creature
        auto* known_creature = getCreature(creature.id);
        if (!known_creature)
        {
          LOG_ERROR("%s: received known creature %u that is not known", __func__, creature.id);
          return;
        }
        known_creature->health_percent = creature.health_percent;
        known_creature->direction = creature.direction;
        known_creature->outfit = creature.outfit;
        known_creature->speed = creature.speed;
      }
      else
      {
        // Remove known creature if set
        if (creature.id_to_remove != 0U)
        {
          LOG_ERROR("%s: remove known creature not yet implemented", __func__);
        }

        // Add new creature
        m_known_creatures.emplace_back();
        m_known_creatures.back().id = creature.id;
        m_known_creatures.back().name = creature.name;
        m_known_creatures.back().health_percent = creature.health_percent;
        m_known_creatures.back().direction = creature.direction;
        m_known_creatures.back().outfit = creature.outfit;
        m_known_creatures.back().speed = creature.speed;

        if (creature.id == m_player_id)
        {
          LOG_INFO("%s: we are %s!", __func__, creature.name.c_str());
        }
      }

      world_tile->things.emplace_back(creature.id);
    }
    else  // Item
    {
      const auto& item = std::get<protocol::Item>(thing);
      const auto& itemtype = (*m_itemtypes)[item.item_type_id];
      Item new_item;
      new_item.type = &itemtype;
      new_item.extra = item.extra;
      Thing t = new_item;
      world_tile->things.push_back(t);
    }
  }
}

Creature* Map::getCreature(common::CreatureId creature_id)
{
  // According to https://stackoverflow.com/a/123995/969365
  const auto* creature = static_cast<const Map*>(this)->getCreature(creature_id);
  return const_cast<Creature*>(creature);
}

Thing Map::getThing(const common::Position& position, std::uint8_t stackpos)
{
  return m_tiles.getTile(position).things[stackpos];
}

void Map::addThing(const common::Position& position, Thing thing)
{
  auto& things = m_tiles.getTile(position).things;
  const auto pre = things.size();
  auto it = things.cbegin() + 1;
  if (std::holds_alternative<Item>(thing))
  {
    const auto& item = std::get<Item>(thing);
    if (item.type->always_on_top)
    {
      // Insert after ground item
      ++it;
    }
    else
    {
      // Find first bottom item or end
      auto it = things.cbegin();
      while (it != things.cend())
      {
        if (std::holds_alternative<Item>(*it) && !std::get<Item>(*it).type->always_on_top)
        {
          break;
        }
        ++it;
      }
    }
  }
  else
  {
    // Find first creature, bottom item or end
    while (it != things.cend())
    {
      if (std::holds_alternative<common::CreatureId>(*it))
      {
        break;
      }
      else if (!std::get<Item>(*it).type->always_on_top)
      {
        break;
      }
      ++it;
    }
  }

  it = things.insert(it, thing);
  const auto post = things.size();

  LOG_INFO("%s: added Thing on position=%s stackpos=%d (size=%d->%d)",
           __func__,
           position.toString().c_str(),
           std::distance(things.cbegin(), it),
           pre,
           post);
}

}  // namespace wsclient::wsworld
<commit_msg>wsclient: update Creature direction on move<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2020 Simon Sandström
 *
 * 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 "wsworld.h"

#include "logger.h"

namespace wsclient::wsworld
{

void Map::setFullMapData(const protocol::client::FullMap& map_data)
{
  // Full map data is width=18, height=14
  m_tiles.setMapPosition(map_data.position);
  auto it = map_data.tiles.begin();
  for (auto x = 0; x < consts::known_tiles_x; x++)
  {
    for (auto y = 0; y < consts::known_tiles_y; y++)
    {
      auto& tile = m_tiles.getTileLocalPos(x, y);
      setTile(*it, &tile);
      ++it;
    }
  }

  m_ready = true;
}

void Map::setPartialMapData(const protocol::client::PartialMap& map_data)
{
  // Set new map position
  const auto old_position = m_tiles.getMapPosition();
  const auto x_diff = map_data.direction == common::Direction::EAST ? 1 : (map_data.direction == common::Direction::WEST ? -1 : 0);
  const auto y_diff = map_data.direction == common::Direction::SOUTH ? 1 : (map_data.direction == common::Direction::NORTH ? -1 : 0);
  const auto new_position = common::Position(old_position.getX() + x_diff,
                                             old_position.getY() + y_diff,
                                             old_position.getZ());
  m_tiles.setMapPosition(new_position);
  LOG_INFO("%s: updated map position from %s to %s",
           __func__,
           old_position.toString().c_str(),
           new_position.toString().c_str());

  // Shift Tiles
  m_tiles.shiftTiles(map_data.direction);

  // Add new Tiles
  auto it = map_data.tiles.begin();
  switch (map_data.direction)
  {
    case common::Direction::NORTH:
      for (auto x = 0; x < consts::known_tiles_x; x++)
      {
        auto& tile = m_tiles.getTileLocalPos(x, 0);
        setTile(*it, &tile);
        ++it;
      }
      break;

    case common::Direction::EAST:
      for (auto y = 0; y < consts::known_tiles_y; y++)
      {
        auto& tile = m_tiles.getTileLocalPos(consts::known_tiles_x - 1, y);
        setTile(*it, &tile);
        ++it;
      }
      break;

    case common::Direction::SOUTH:
      for (auto x = 0; x < consts::known_tiles_x; x++)
      {
        auto& tile = m_tiles.getTileLocalPos(x, consts::known_tiles_y - 1);
        setTile(*it, &tile);
        ++it;
      }
      break;

    case common::Direction::WEST:
      for (auto y = 0; y < consts::known_tiles_y; y++)
      {
        auto& tile = m_tiles.getTileLocalPos(0, y);
        setTile(*it, &tile);
        ++it;
      }
      break;
  }
}

void Map::addCreature(const common::Position& position, common::CreatureId creature_id)
{
  addThing(position, creature_id);
}

void Map::addCreature(const common::Position& position, const protocol::Creature& creature)
{
  // TODO: add to known creatures if needed?
  addCreature(position, creature.id);
}

void Map::addItem(const common::Position& position,
                  common::ItemTypeId item_type_id,
                  std::uint8_t extra,
                  bool onTop)
{
  // TODO: why is onTop sent here?
  (void)onTop;

  Item item;
  item.type = &((*m_itemtypes)[item_type_id]);
  item.extra = extra;
  addThing(position, item);
}

void Map::removeThing(const common::Position& position, std::uint8_t stackpos)
{
  const auto pre = m_tiles.getTile(position).things.size();
  auto& things = m_tiles.getTile(position).things;
  things.erase(things.cbegin() + stackpos);
  const auto post = m_tiles.getTile(position).things.size();

  LOG_INFO("%s: removed thing from position=%s stackpos=%d (size=%d->%d)",
           __func__,
           position.toString().c_str(),
           stackpos,
           pre,
           post);
}

void Map::moveThing(const common::Position& from_position,
                    std::uint8_t from_stackpos,
                    const common::Position& to_position)
{
  const auto thing = getThing(from_position, from_stackpos);
  removeThing(from_position, from_stackpos);
  if (std::holds_alternative<common::CreatureId>(thing))
  {
    // Rotate Creature based on movement
    // TODO: handle diagonal movement
    auto* creature = getCreature(std::get<common::CreatureId>(thing));
    if (from_position.getX() > to_position.getX())
    {
      creature->direction = common::Direction::WEST;
    }
    else if (from_position.getX() < to_position.getX())
    {
      creature->direction = common::Direction::EAST;
    }
    else if (from_position.getY() > to_position.getY())
    {
      creature->direction = common::Direction::NORTH;
    }
    else if (from_position.getY() < to_position.getY())
    {
      creature->direction = common::Direction::SOUTH;
    }
  }
  addThing(to_position, thing);
}

const Tile& Map::getTile(const common::Position& position) const
{
  return m_tiles.getTile(position);
}

const Creature* Map::getCreature(common::CreatureId creature_id) const
{
  auto it = std::find_if(m_known_creatures.cbegin(),
                         m_known_creatures.cend(),
                         [creature_id](const Creature& creature)
  {
    return creature_id == creature.id;
  });
  if (it == m_known_creatures.cend())
  {
    return nullptr;
  }
  return &(*it);
}

void Map::setTile(const protocol::Tile& protocol_tile, Tile* world_tile)
{
  world_tile->things.clear();
  if (protocol_tile.skip)
  {
    return;
  }

  for (const auto& thing : protocol_tile.things)
  {
    if (std::holds_alternative<protocol::Creature>(thing))
    {
      const auto& creature = std::get<protocol::Creature>(thing);
      if (creature.known)
      {
        // Update known creature
        auto* known_creature = getCreature(creature.id);
        if (!known_creature)
        {
          LOG_ERROR("%s: received known creature %u that is not known", __func__, creature.id);
          return;
        }
        known_creature->health_percent = creature.health_percent;
        known_creature->direction = creature.direction;
        known_creature->outfit = creature.outfit;
        known_creature->speed = creature.speed;
      }
      else
      {
        // Remove known creature if set
        if (creature.id_to_remove != 0U)
        {
          LOG_ERROR("%s: remove known creature not yet implemented", __func__);
        }

        // Add new creature
        m_known_creatures.emplace_back();
        m_known_creatures.back().id = creature.id;
        m_known_creatures.back().name = creature.name;
        m_known_creatures.back().health_percent = creature.health_percent;
        m_known_creatures.back().direction = creature.direction;
        m_known_creatures.back().outfit = creature.outfit;
        m_known_creatures.back().speed = creature.speed;

        if (creature.id == m_player_id)
        {
          LOG_INFO("%s: we are %s!", __func__, creature.name.c_str());
        }
      }

      world_tile->things.emplace_back(creature.id);
    }
    else  // Item
    {
      const auto& item = std::get<protocol::Item>(thing);
      const auto& itemtype = (*m_itemtypes)[item.item_type_id];
      Item new_item;
      new_item.type = &itemtype;
      new_item.extra = item.extra;
      Thing t = new_item;
      world_tile->things.push_back(t);
    }
  }
}

Creature* Map::getCreature(common::CreatureId creature_id)
{
  // According to https://stackoverflow.com/a/123995/969365
  const auto* creature = static_cast<const Map*>(this)->getCreature(creature_id);
  return const_cast<Creature*>(creature);
}

Thing Map::getThing(const common::Position& position, std::uint8_t stackpos)
{
  return m_tiles.getTile(position).things[stackpos];
}

void Map::addThing(const common::Position& position, Thing thing)
{
  auto& things = m_tiles.getTile(position).things;
  const auto pre = things.size();
  auto it = things.cbegin() + 1;
  if (std::holds_alternative<Item>(thing))
  {
    const auto& item = std::get<Item>(thing);
    if (item.type->always_on_top)
    {
      // Insert after ground item
      ++it;
    }
    else
    {
      // Find first bottom item or end
      auto it = things.cbegin();
      while (it != things.cend())
      {
        if (std::holds_alternative<Item>(*it) && !std::get<Item>(*it).type->always_on_top)
        {
          break;
        }
        ++it;
      }
    }
  }
  else
  {
    // Find first creature, bottom item or end
    while (it != things.cend())
    {
      if (std::holds_alternative<common::CreatureId>(*it))
      {
        break;
      }
      else if (!std::get<Item>(*it).type->always_on_top)
      {
        break;
      }
      ++it;
    }
  }

  it = things.insert(it, thing);
  const auto post = things.size();

  LOG_INFO("%s: added Thing on position=%s stackpos=%d (size=%d->%d)",
           __func__,
           position.toString().c_str(),
           std::distance(things.cbegin(), it),
           pre,
           post);
}

}  // namespace wsclient::wsworld
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Christian Schulte <schulte@gecode.org>
 *
 *  Copyright:
 *     Christian Schulte, 2009
 *
 *  Last modified:
 *     $Date$ by $Author$
 *     $Revision$
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *  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.
 *
 */

#ifdef GECODE_HAS_UNISTD_H
#include <unistd.h>
#endif

namespace Gecode { namespace Support {

  /*
   * Mutex
   */
  forceinline
  Mutex::Mutex(void) {
    if (pthread_mutex_init(&p_m,NULL) != 0)
      throw OperatingSystemError("Mutex::Mutex[pthread_mutex_init]");
  }
  forceinline void
  Mutex::acquire(void) {
    if (pthread_mutex_lock(&p_m) != 0)
      throw OperatingSystemError("Mutex::acquire[pthread_mutex_lock]");
  }
  forceinline bool
  Mutex::tryacquire(void) {
    return pthread_mutex_trylock(&p_m) == 0;
  }
  forceinline void
  Mutex::release(void) {
    if (pthread_mutex_unlock(&p_m) != 0)
      throw OperatingSystemError("Mutex::release[pthread_mutex_unlock]");
  }
  forceinline
  Mutex::~Mutex(void) {
    if (pthread_mutex_destroy(&p_m) != 0)
      throw OperatingSystemError("Mutex::~Mutex[pthread_mutex_destroy]");
  }

#ifdef GECODE_THREADS_OSX

  /*
   * FastMutex
   */
  forceinline
  FastMutex::FastMutex(void) {}
  forceinline void
  FastMutex::acquire(void) {
    OSSpinLockLock(&lck);
  }
  forceinline bool
  FastMutex::tryacquire(void) {
    return OSSpinLockTry(&lck);
  }
  forceinline void
  FastMutex::release(void) {
    OSSpinLockUnlock(&lck);
  }
  forceinline
  FastMutex::~FastMutex(void) {}

#endif

#ifdef GECODE_THREADS_PTHREADS_SPINLOCK

  /*
   * FastMutex
   */
  forceinline
  FastMutex::FastMutex(void) {
    if (pthread_spin_init(&p_s,PTHREAD_PROCESS_PRIVATE) != 0)
      throw OperatingSystemError("FastMutex::FastMutex[pthread_spin_init]");
  }
  forceinline void
  FastMutex::acquire(void) {
    if (pthread_spin_lock(&p_s) != 0)
      throw OperatingSystemError("FastMutex::acquire[pthread_spin_lock]");
  }
  forceinline bool
  FastMutex::tryacquire(void) {
    return pthread_spin_trylock(&p_s) == 0;
  }
  forceinline void
  FastMutex::release(void) {
    if (pthread_spin_unlock(&p_s) != 0)
      throw OperatingSystemError("FastMutex::release[pthread_spin_unlock]");
  }
  forceinline
  FastMutex::~FastMutex(void) {
    if (pthread_spin_destroy(&p_s) != 0)
      throw OperatingSystemError(
        "FastMutex::~FastMutex[pthread_spin_destroy]");
  }

#endif

  /*
   * Event
   */
  forceinline
  Event::Event(void) : p_s(false) {
    if (pthread_mutex_init(&p_m,NULL) != 0)
      throw OperatingSystemError("Event::Event[pthread_mutex_init]");
    if (pthread_cond_init(&p_c,NULL) != 0)
      throw OperatingSystemError("Event::Event[pthread_cond_init]");
  }
  forceinline void
  Event::signal(void) {
    if (pthread_mutex_lock(&p_m) != 0)
      throw OperatingSystemError("Event::signal[pthread_mutex_lock]");
    if (!p_s) {
      p_s = true;
      if (pthread_cond_signal(&p_c) != 0)
        throw OperatingSystemError("Event::signal[pthread_cond_signal]");
    }
    if (pthread_mutex_unlock(&p_m) != 0)
      throw OperatingSystemError("Event::signal[pthread_mutex_unlock]");
  }
  forceinline void
  Event::wait(void) {
    if (pthread_mutex_lock(&p_m) != 0)
      throw OperatingSystemError("Event::wait[pthread_mutex_lock]");
    while (!p_s)
      if (pthread_cond_wait(&p_c,&p_m) != 0)
        throw OperatingSystemError("Event::wait[pthread_cond_wait]");
    p_s = false;
    if (pthread_mutex_unlock(&p_m) != 0)
      throw OperatingSystemError("Event::wait[pthread_mutex_unlock]");
  }
  forceinline
  Event::~Event(void) {
    if (pthread_cond_destroy(&p_c) != 0)
      throw OperatingSystemError("Event::~Event[pthread_cond_destroy]");
    if (pthread_mutex_destroy(&p_m) != 0)
      throw OperatingSystemError("Event::~Event[pthread_mutex_destroy]");
  }

  /*
   * Thread
   */
  forceinline void
  Thread::sleep(unsigned int ms) {
#ifdef GECODE_HAS_UNISTD_H
    unsigned int s = ms / 1000;
    ms -= 1000 * s;
    if (s > 0) {
      // More than one million microseconds, use sleep
      ::sleep(s);
    }
    usleep(ms * 1000);
#endif
  }
  forceinline unsigned int
  Thread::npu(void) {
#ifdef GECODE_HAS_UNISTD_H
    int n=static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
    return (n>1) ? n : 1;
#else
    return 1;
#endif
  }

}}

// STATISTICS: support-any
<commit_msg>Initialise spin lock<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Christian Schulte <schulte@gecode.org>
 *
 *  Copyright:
 *     Christian Schulte, 2009
 *
 *  Last modified:
 *     $Date$ by $Author$
 *     $Revision$
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *  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.
 *
 */

#ifdef GECODE_HAS_UNISTD_H
#include <unistd.h>
#endif

namespace Gecode { namespace Support {

  /*
   * Mutex
   */
  forceinline
  Mutex::Mutex(void) {
    if (pthread_mutex_init(&p_m,NULL) != 0)
      throw OperatingSystemError("Mutex::Mutex[pthread_mutex_init]");
  }
  forceinline void
  Mutex::acquire(void) {
    if (pthread_mutex_lock(&p_m) != 0)
      throw OperatingSystemError("Mutex::acquire[pthread_mutex_lock]");
  }
  forceinline bool
  Mutex::tryacquire(void) {
    return pthread_mutex_trylock(&p_m) == 0;
  }
  forceinline void
  Mutex::release(void) {
    if (pthread_mutex_unlock(&p_m) != 0)
      throw OperatingSystemError("Mutex::release[pthread_mutex_unlock]");
  }
  forceinline
  Mutex::~Mutex(void) {
    if (pthread_mutex_destroy(&p_m) != 0)
      throw OperatingSystemError("Mutex::~Mutex[pthread_mutex_destroy]");
  }

#ifdef GECODE_THREADS_OSX

  /*
   * FastMutex
   */
  forceinline
  FastMutex::FastMutex(void) : lck(OS_SPINLOCK_INIT) {}
  forceinline void
  FastMutex::acquire(void) {
    OSSpinLockLock(&lck);
  }
  forceinline bool
  FastMutex::tryacquire(void) {
    return OSSpinLockTry(&lck);
  }
  forceinline void
  FastMutex::release(void) {
    OSSpinLockUnlock(&lck);
  }
  forceinline
  FastMutex::~FastMutex(void) {}

#endif

#ifdef GECODE_THREADS_PTHREADS_SPINLOCK

  /*
   * FastMutex
   */
  forceinline
  FastMutex::FastMutex(void) {
    if (pthread_spin_init(&p_s,PTHREAD_PROCESS_PRIVATE) != 0)
      throw OperatingSystemError("FastMutex::FastMutex[pthread_spin_init]");
  }
  forceinline void
  FastMutex::acquire(void) {
    if (pthread_spin_lock(&p_s) != 0)
      throw OperatingSystemError("FastMutex::acquire[pthread_spin_lock]");
  }
  forceinline bool
  FastMutex::tryacquire(void) {
    return pthread_spin_trylock(&p_s) == 0;
  }
  forceinline void
  FastMutex::release(void) {
    if (pthread_spin_unlock(&p_s) != 0)
      throw OperatingSystemError("FastMutex::release[pthread_spin_unlock]");
  }
  forceinline
  FastMutex::~FastMutex(void) {
    if (pthread_spin_destroy(&p_s) != 0)
      throw OperatingSystemError(
        "FastMutex::~FastMutex[pthread_spin_destroy]");
  }

#endif

  /*
   * Event
   */
  forceinline
  Event::Event(void) : p_s(false) {
    if (pthread_mutex_init(&p_m,NULL) != 0)
      throw OperatingSystemError("Event::Event[pthread_mutex_init]");
    if (pthread_cond_init(&p_c,NULL) != 0)
      throw OperatingSystemError("Event::Event[pthread_cond_init]");
  }
  forceinline void
  Event::signal(void) {
    if (pthread_mutex_lock(&p_m) != 0)
      throw OperatingSystemError("Event::signal[pthread_mutex_lock]");
    if (!p_s) {
      p_s = true;
      if (pthread_cond_signal(&p_c) != 0)
        throw OperatingSystemError("Event::signal[pthread_cond_signal]");
    }
    if (pthread_mutex_unlock(&p_m) != 0)
      throw OperatingSystemError("Event::signal[pthread_mutex_unlock]");
  }
  forceinline void
  Event::wait(void) {
    if (pthread_mutex_lock(&p_m) != 0)
      throw OperatingSystemError("Event::wait[pthread_mutex_lock]");
    while (!p_s)
      if (pthread_cond_wait(&p_c,&p_m) != 0)
        throw OperatingSystemError("Event::wait[pthread_cond_wait]");
    p_s = false;
    if (pthread_mutex_unlock(&p_m) != 0)
      throw OperatingSystemError("Event::wait[pthread_mutex_unlock]");
  }
  forceinline
  Event::~Event(void) {
    if (pthread_cond_destroy(&p_c) != 0)
      throw OperatingSystemError("Event::~Event[pthread_cond_destroy]");
    if (pthread_mutex_destroy(&p_m) != 0)
      throw OperatingSystemError("Event::~Event[pthread_mutex_destroy]");
  }

  /*
   * Thread
   */
  forceinline void
  Thread::sleep(unsigned int ms) {
#ifdef GECODE_HAS_UNISTD_H
    unsigned int s = ms / 1000;
    ms -= 1000 * s;
    if (s > 0) {
      // More than one million microseconds, use sleep
      ::sleep(s);
    }
    usleep(ms * 1000);
#endif
  }
  forceinline unsigned int
  Thread::npu(void) {
#ifdef GECODE_HAS_UNISTD_H
    int n=static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
    return (n>1) ? n : 1;
#else
    return 1;
#endif
  }

}}

// STATISTICS: support-any
<|endoftext|>


<commit_before>/*
Copyright (c) 2015-2021 Alternative Games Ltd / Turo Lamminen

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.
*/

#ifdef RENDERER_NULL

#include "RendererInternal.h"
#include "utils/Utils.h"

namespace renderer {

RendererImpl::RendererImpl(const RendererDesc &desc)
: RendererBase(desc)
{
	SDL_Init(SDL_INIT_EVENTS);

	swapchainFormat = Format::sRGBA8;

	currentRefreshRate = 60;
	maxRefreshRate     = 60;

	recreateRingBuffer(desc.ephemeralRingBufSize);

	frames.resize(desc.swapchain.numFrames);
}

void RendererImpl::recreateRingBuffer(unsigned int newSize) {
	assert(newSize > 0);

	ringBufPtr  = 0;
	ringBufSize = newSize;
	ringBuffer.resize(newSize, 0);
	LOG_TODO("use valgrind to make sure we only write to intended parts of ring buffer");
}

RendererImpl::~RendererImpl() {
	waitForDeviceIdle();

	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		assert(!f.outstanding);
		deleteFrameInternal(f);
	}
	frames.clear();

	SDL_Quit();
}

bool Renderer::isRenderTargetFormatSupported(Format /* format */) const {
	LOG_TODO("actually check it...");
	return true;
}

BufferHandle Renderer::createBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	auto result            = impl->buffers.add();
	Buffer &buffer         = result.first;
	buffer.ringBufferAlloc = false;
	buffer.beginOffs       = 0;
	buffer.size            = size;

	LOG_TODO("store contents into buffer");

	return result.second;
}

BufferHandle Renderer::createEphemeralBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	unsigned int beginPtr = impl->ringBufferAllocate(size, 256);

	LOG_TODO("use valgrind to enforce we only write to intended parts of ring buffer");
	memcpy(&impl->ringBuffer[beginPtr], contents, size);

	auto result    = impl->buffers.add();
	Buffer &buffer = result.first;
	buffer.ringBufferAlloc = true;
	buffer.beginOffs       = beginPtr;
	buffer.size            = size;

	impl->frames.at(impl->currentFrameIdx).ephemeralBuffers.push_back(result.second);

	return result.second;
}

FramebufferHandle Renderer::createFramebuffer(const FramebufferDesc &desc) {
	auto result = impl->framebuffers.add();
	auto &fb = result.first;
	fb.renderPass = desc.renderPass_;

	return result.second;
}

RenderPassHandle Renderer::createRenderPass(const RenderPassDesc &desc) {
	auto result = impl->renderpasses.add();
	auto &rp    = result.first;
	rp.desc     = desc;

	return result.second;
}

PipelineHandle Renderer::createPipeline(const PipelineDesc &desc) {
	auto result = impl->pipelines.add();
	auto &pipeline = result.first;
	pipeline.desc = desc;
	return result.second;
}

RenderTargetHandle Renderer::createRenderTarget(const RenderTargetDesc &desc) {
	assert(desc.width_  > 0);
	assert(desc.height_ > 0);
	assert(desc.format_ != +Format::Invalid);

	auto result = impl->rendertargets.add();
	auto &rendertarget = result.first;
	rendertarget.desc = desc;
	return result.second;
}

SamplerHandle Renderer::createSampler(const SamplerDesc &desc) {
	auto result = impl->samplers.add();
	Sampler &sampler = result.first;
	LOG_TODO("check desc");
	sampler.desc = desc;

	return result.second;
}

VertexShaderHandle RendererImpl::createVertexShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string vertexShaderName   = name + ".vert";

	auto result_ = vertexShaders.add();
	auto &v = result_.first;
	v.name      = vertexShaderName;

	return result_.second;
}

FragmentShaderHandle RendererImpl::createFragmentShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string fragmentShaderName = name + ".frag";

	auto result_ = fragmentShaders.add();
	auto &f = result_.first;
	f.name      = fragmentShaderName;

	return result_.second;
}

TextureHandle Renderer::createTexture(const TextureDesc &desc) {
	assert(desc.width_   > 0);
	assert(desc.height_  > 0);
	assert(desc.numMips_ > 0);

	LOG_TODO("check data");

	auto result = impl->textures.add();
	Texture &texture = result.first;
	LOG_TODO("check desc");
	texture.desc = desc;

	return result.second;
}

DSLayoutHandle Renderer::createDescriptorSetLayout(const DescriptorLayout *layout) {
	auto result = impl->dsLayouts.add();
	DescriptorSetLayout &dsLayout = result.first;

	while (layout->type != +DescriptorType::End) {
		dsLayout.layout.push_back(*layout);
		layout++;
	}
	assert(layout->offset == 0);

	return result.second;
}

TextureHandle Renderer::getRenderTargetView(RenderTargetHandle /* handle */, Format /* f */) {
	TextureHandle handle;

	return handle;
}

void Renderer::deleteBuffer(BufferHandle & /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle & /*  */) {
}

void Renderer::deletePipeline(PipelineHandle & /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle & /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle & /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle & /* handle */) {
}

void Renderer::deleteTexture(TextureHandle & /* handle */) {
}

void Renderer::deleteBuffer(BufferHandle && /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle && /*  */) {
}

void Renderer::deletePipeline(PipelineHandle && /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle && /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle && /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle && /* handle */) {
}

void Renderer::deleteTexture(TextureHandle && /* handle */) {
}

void Renderer::setSwapchainDesc(const SwapchainDesc &desc) {
	impl->swapchainDesc  = desc;
}

glm::uvec2 Renderer::getDrawableSize() const {
	return glm::uvec2(impl->swapchainDesc.width, impl->swapchainDesc.height);
}

MemoryStats Renderer::getMemStats() const {
	MemoryStats stats;
	return stats;
}

void RendererImpl::waitForDeviceIdle() {
	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		if (f.outstanding) {
			// try to wait
			waitForFrame(i);
			assert(!f.outstanding);
		}
	}
}

void Renderer::beginFrame() {
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::beginRenderPassSwapchain(RenderPassHandle rpHandle) {
	assert(rpHandle);
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	assert(!impl->renderingToSwapchain);
	impl->renderingToSwapchain = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::presentFrame() {
	assert(impl->inFrame);
	impl->inFrame = false;

	auto &frame = impl->frames.at(impl->currentFrameIdx);

	frame.usedRingBufPtr = impl->ringBufPtr;
	frame.outstanding    = true;
	frame.lastFrameNum   = impl->frameNum;

	impl->frameNum++;
}

void RendererImpl::waitForFrame(unsigned int frameIdx) {
	assert(frameIdx < frames.size());

	Frame &frame = frames.at(frameIdx);
	assert(frame.outstanding);

	for (auto handle : frame.ephemeralBuffers) {
		Buffer &buffer = buffers.get(handle);
		if (buffer.ringBufferAlloc) {
			buffer.ringBufferAlloc = false;
		}

		assert(buffer.size   >  0);
		buffer.size = 0;
		buffer.beginOffs = 0;

		buffers.remove(handle);
	}
	frame.ephemeralBuffers.clear();
	frame.outstanding    = false;
	lastSyncedFrame      = std::max(lastSyncedFrame, frame.lastFrameNum);
	lastSyncedRingBufPtr = std::max(lastSyncedRingBufPtr, frame.usedRingBufPtr);
}

void RendererImpl::deleteFrameInternal(Frame &f) {
	assert(!f.outstanding);
}

void Renderer::beginRenderPass(RenderPassHandle rpHandle, FramebufferHandle fbHandle) {
	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);

	impl->inRenderPass  = true;
	impl->validPipeline = false;

	assert(fbHandle);
	const auto &fb = impl->framebuffers.get(fbHandle);

	// make sure renderpass and framebuffer match
	assert(fb.renderPass == rpHandle);
}

void Renderer::endRenderPass() {
	assert(impl->inFrame);
	assert(impl->inRenderPass);
	impl->inRenderPass = false;
	impl->renderingToSwapchain = false;
}

void Renderer::layoutTransition(RenderTargetHandle image, Layout src, Layout dest) {
	assert(image);
	assert(dest != +Layout::Undefined);
	assert(src != dest);
}

void Renderer::bindPipeline(PipelineHandle pipeline) {
	assert(impl->inFrame);
	assert(pipeline);
	assert(impl->inRenderPass);
	assert(impl->pipelineDrawn);
	impl->pipelineDrawn = false;
	impl->validPipeline = true;
	impl->scissorSet    = false;

	impl->currentPipeline = impl->pipelines.get(pipeline).desc;
}

void Renderer::bindIndexBuffer(BufferHandle /* buffer */, bool /* bit16 */ ) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindVertexBuffer(unsigned int /* binding */, BufferHandle /* buffer */) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindDescriptorSet(unsigned int /* index */, DSLayoutHandle /* layout */, const void * /* data_ */) {
	assert(impl->validPipeline);
}

void Renderer::setViewport(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->inFrame);
}

void Renderer::setScissorRect(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->validPipeline);
	assert(impl->currentPipeline.scissorTest_);
	impl->scissorSet = true;
}

void Renderer::blit(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAA(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAAToSwapchain(RenderTargetHandle source, Layout finalLayout) {
	assert(source);
	assert(finalLayout != +Layout::Undefined);

	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);
}

void Renderer::draw(unsigned int /* firstVertex */, unsigned int vertexCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedInstanced(unsigned int vertexCount, unsigned int instanceCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(instanceCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedOffset(unsigned int vertexCount, unsigned int /* firstIndex */, unsigned int /* minIndex */, unsigned int /* maxIndex */) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

} // namespace renderer

#endif //  RENDERER_NULL
<commit_msg>Refactor null Renderer::createDescriptorSetLayout<commit_after>/*
Copyright (c) 2015-2021 Alternative Games Ltd / Turo Lamminen

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.
*/

#ifdef RENDERER_NULL

#include "RendererInternal.h"
#include "utils/Utils.h"

namespace renderer {

RendererImpl::RendererImpl(const RendererDesc &desc)
: RendererBase(desc)
{
	SDL_Init(SDL_INIT_EVENTS);

	swapchainFormat = Format::sRGBA8;

	currentRefreshRate = 60;
	maxRefreshRate     = 60;

	recreateRingBuffer(desc.ephemeralRingBufSize);

	frames.resize(desc.swapchain.numFrames);
}

void RendererImpl::recreateRingBuffer(unsigned int newSize) {
	assert(newSize > 0);

	ringBufPtr  = 0;
	ringBufSize = newSize;
	ringBuffer.resize(newSize, 0);
	LOG_TODO("use valgrind to make sure we only write to intended parts of ring buffer");
}

RendererImpl::~RendererImpl() {
	waitForDeviceIdle();

	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		assert(!f.outstanding);
		deleteFrameInternal(f);
	}
	frames.clear();

	SDL_Quit();
}

bool Renderer::isRenderTargetFormatSupported(Format /* format */) const {
	LOG_TODO("actually check it...");
	return true;
}

BufferHandle Renderer::createBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	auto result            = impl->buffers.add();
	Buffer &buffer         = result.first;
	buffer.ringBufferAlloc = false;
	buffer.beginOffs       = 0;
	buffer.size            = size;

	LOG_TODO("store contents into buffer");

	return result.second;
}

BufferHandle Renderer::createEphemeralBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	unsigned int beginPtr = impl->ringBufferAllocate(size, 256);

	LOG_TODO("use valgrind to enforce we only write to intended parts of ring buffer");
	memcpy(&impl->ringBuffer[beginPtr], contents, size);

	auto result    = impl->buffers.add();
	Buffer &buffer = result.first;
	buffer.ringBufferAlloc = true;
	buffer.beginOffs       = beginPtr;
	buffer.size            = size;

	impl->frames.at(impl->currentFrameIdx).ephemeralBuffers.push_back(result.second);

	return result.second;
}

FramebufferHandle Renderer::createFramebuffer(const FramebufferDesc &desc) {
	auto result = impl->framebuffers.add();
	auto &fb = result.first;
	fb.renderPass = desc.renderPass_;

	return result.second;
}

RenderPassHandle Renderer::createRenderPass(const RenderPassDesc &desc) {
	auto result = impl->renderpasses.add();
	auto &rp    = result.first;
	rp.desc     = desc;

	return result.second;
}

PipelineHandle Renderer::createPipeline(const PipelineDesc &desc) {
	auto result = impl->pipelines.add();
	auto &pipeline = result.first;
	pipeline.desc = desc;
	return result.second;
}

RenderTargetHandle Renderer::createRenderTarget(const RenderTargetDesc &desc) {
	assert(desc.width_  > 0);
	assert(desc.height_ > 0);
	assert(desc.format_ != +Format::Invalid);

	auto result = impl->rendertargets.add();
	auto &rendertarget = result.first;
	rendertarget.desc = desc;
	return result.second;
}

SamplerHandle Renderer::createSampler(const SamplerDesc &desc) {
	auto result = impl->samplers.add();
	Sampler &sampler = result.first;
	LOG_TODO("check desc");
	sampler.desc = desc;

	return result.second;
}

VertexShaderHandle RendererImpl::createVertexShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string vertexShaderName   = name + ".vert";

	auto result_ = vertexShaders.add();
	auto &v = result_.first;
	v.name      = vertexShaderName;

	return result_.second;
}

FragmentShaderHandle RendererImpl::createFragmentShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string fragmentShaderName = name + ".frag";

	auto result_ = fragmentShaders.add();
	auto &f = result_.first;
	f.name      = fragmentShaderName;

	return result_.second;
}

TextureHandle Renderer::createTexture(const TextureDesc &desc) {
	assert(desc.width_   > 0);
	assert(desc.height_  > 0);
	assert(desc.numMips_ > 0);

	LOG_TODO("check data");

	auto result = impl->textures.add();
	Texture &texture = result.first;
	LOG_TODO("check desc");
	texture.desc = desc;

	return result.second;
}

DSLayoutHandle Renderer::createDescriptorSetLayout(const DescriptorLayout *layout) {
	DescriptorSetLayout dsLayout;

	while (layout->type != +DescriptorType::End) {
		dsLayout.layout.push_back(*layout);
		layout++;
	}
	assert(layout->offset == 0);

	return impl->dsLayouts.add(std::move(dsLayout));
}

TextureHandle Renderer::getRenderTargetView(RenderTargetHandle /* handle */, Format /* f */) {
	TextureHandle handle;

	return handle;
}

void Renderer::deleteBuffer(BufferHandle & /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle & /*  */) {
}

void Renderer::deletePipeline(PipelineHandle & /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle & /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle & /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle & /* handle */) {
}

void Renderer::deleteTexture(TextureHandle & /* handle */) {
}

void Renderer::deleteBuffer(BufferHandle && /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle && /*  */) {
}

void Renderer::deletePipeline(PipelineHandle && /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle && /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle && /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle && /* handle */) {
}

void Renderer::deleteTexture(TextureHandle && /* handle */) {
}

void Renderer::setSwapchainDesc(const SwapchainDesc &desc) {
	impl->swapchainDesc  = desc;
}

glm::uvec2 Renderer::getDrawableSize() const {
	return glm::uvec2(impl->swapchainDesc.width, impl->swapchainDesc.height);
}

MemoryStats Renderer::getMemStats() const {
	MemoryStats stats;
	return stats;
}

void RendererImpl::waitForDeviceIdle() {
	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		if (f.outstanding) {
			// try to wait
			waitForFrame(i);
			assert(!f.outstanding);
		}
	}
}

void Renderer::beginFrame() {
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::beginRenderPassSwapchain(RenderPassHandle rpHandle) {
	assert(rpHandle);
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	assert(!impl->renderingToSwapchain);
	impl->renderingToSwapchain = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::presentFrame() {
	assert(impl->inFrame);
	impl->inFrame = false;

	auto &frame = impl->frames.at(impl->currentFrameIdx);

	frame.usedRingBufPtr = impl->ringBufPtr;
	frame.outstanding    = true;
	frame.lastFrameNum   = impl->frameNum;

	impl->frameNum++;
}

void RendererImpl::waitForFrame(unsigned int frameIdx) {
	assert(frameIdx < frames.size());

	Frame &frame = frames.at(frameIdx);
	assert(frame.outstanding);

	for (auto handle : frame.ephemeralBuffers) {
		Buffer &buffer = buffers.get(handle);
		if (buffer.ringBufferAlloc) {
			buffer.ringBufferAlloc = false;
		}

		assert(buffer.size   >  0);
		buffer.size = 0;
		buffer.beginOffs = 0;

		buffers.remove(handle);
	}
	frame.ephemeralBuffers.clear();
	frame.outstanding    = false;
	lastSyncedFrame      = std::max(lastSyncedFrame, frame.lastFrameNum);
	lastSyncedRingBufPtr = std::max(lastSyncedRingBufPtr, frame.usedRingBufPtr);
}

void RendererImpl::deleteFrameInternal(Frame &f) {
	assert(!f.outstanding);
}

void Renderer::beginRenderPass(RenderPassHandle rpHandle, FramebufferHandle fbHandle) {
	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);

	impl->inRenderPass  = true;
	impl->validPipeline = false;

	assert(fbHandle);
	const auto &fb = impl->framebuffers.get(fbHandle);

	// make sure renderpass and framebuffer match
	assert(fb.renderPass == rpHandle);
}

void Renderer::endRenderPass() {
	assert(impl->inFrame);
	assert(impl->inRenderPass);
	impl->inRenderPass = false;
	impl->renderingToSwapchain = false;
}

void Renderer::layoutTransition(RenderTargetHandle image, Layout src, Layout dest) {
	assert(image);
	assert(dest != +Layout::Undefined);
	assert(src != dest);
}

void Renderer::bindPipeline(PipelineHandle pipeline) {
	assert(impl->inFrame);
	assert(pipeline);
	assert(impl->inRenderPass);
	assert(impl->pipelineDrawn);
	impl->pipelineDrawn = false;
	impl->validPipeline = true;
	impl->scissorSet    = false;

	impl->currentPipeline = impl->pipelines.get(pipeline).desc;
}

void Renderer::bindIndexBuffer(BufferHandle /* buffer */, bool /* bit16 */ ) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindVertexBuffer(unsigned int /* binding */, BufferHandle /* buffer */) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindDescriptorSet(unsigned int /* index */, DSLayoutHandle /* layout */, const void * /* data_ */) {
	assert(impl->validPipeline);
}

void Renderer::setViewport(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->inFrame);
}

void Renderer::setScissorRect(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->validPipeline);
	assert(impl->currentPipeline.scissorTest_);
	impl->scissorSet = true;
}

void Renderer::blit(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAA(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAAToSwapchain(RenderTargetHandle source, Layout finalLayout) {
	assert(source);
	assert(finalLayout != +Layout::Undefined);

	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);
}

void Renderer::draw(unsigned int /* firstVertex */, unsigned int vertexCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedInstanced(unsigned int vertexCount, unsigned int instanceCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(instanceCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedOffset(unsigned int vertexCount, unsigned int /* firstIndex */, unsigned int /* minIndex */, unsigned int /* maxIndex */) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

} // namespace renderer

#endif //  RENDERER_NULL
<|endoftext|>