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

#if     qHasFeature_libcurl
#include    <curl/curl.h>
#endif

#include    "../../../Characters/Format.h"
#include    "../../../Characters/String_Constant.h"
#include    "../../../Debug/Trace.h"
#include    "../../../Execution/Exceptions.h"

#include    "../HTTP/Methods.h"

#include    "Client_libcurl.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;
using   namespace   Stroika::Foundation::Execution;
using   namespace   Stroika::Foundation::IO;
using   namespace   Stroika::Foundation::IO::Network;
using   namespace   Stroika::Foundation::IO::Network::Transfer;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

// Uncomment this line to enable libcurl to print diagnostics to stderr
//#define       USE_LIBCURL_VERBOSE_    1

#if     qHasFeature_libcurl
namespace   {
    struct  ModuleInit_ {
        ModuleInit_ ()
        {
            ::curl_global_init (CURL_GLOBAL_ALL);
        }
    };
    ModuleInit_ sIniter_;
}
#endif

#if     qHasFeature_libcurl
class   Connection_LibCurl::Rep_ : public _IRep {
public:
    Connection::Options fOptions;

public:
    Rep_ (const Connection::Options& options)
        : fOptions (options)
    {
    }
    Rep_ (const Rep_&) = delete;
    virtual ~Rep_ ();

public:
    nonvirtual  Rep_& operator= (const Rep_&) = delete;

public:
    virtual DurationSecondsType GetTimeout () const override;
    virtual void                SetTimeout (DurationSecondsType timeout) override;
    virtual URL                 GetURL () const override;
    virtual void                SetURL (const URL& url) override;
    virtual void                Close ()    override;
    virtual Response            Send (const Request& request) override;

private:
    nonvirtual  void    MakeHandleIfNeeded_ ();

private:
    static      size_t  s_RequestPayloadReadHandler_ (char* buffer, size_t size, size_t nitems, void* userP);
    nonvirtual  size_t  RequestPayloadReadHandler_ (Byte* buffer, size_t bufSize);

private:
    static      size_t  s_ResponseWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP);
    nonvirtual  size_t  ResponseWriteHandler_ (const Byte* ptr, size_t nBytes);

private:
    static      size_t  s_ResponseHeaderWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP);
    nonvirtual  size_t  ResponseHeaderWriteHandler_ (const Byte* ptr, size_t nBytes);

private:
    void*                   fCurlHandle_ { nullptr };
    string                  fCURLCacheUTF8_URL_;    // cuz of quirky memory management policies of libcurl
    string                  fCURLCacheUTF8_Method_;     // cuz of quirky memory management policies of libcurl
    vector<Byte>            fUploadData_;
    size_t                  fUploadDataCursor_ {};
    vector<Byte>            fResponseData_;
    Mapping<String, String> fResponseHeaders_;
    curl_slist*             fSavedHeaders_ { nullptr };
};
#endif

#if     qHasFeature_libcurl
namespace   {
    wstring mkExceptMsg_ (LibCurlException::CURLcode ccode)
    {
        return String::FromUTF8 (curl_easy_strerror (static_cast<CURLcode> (ccode))).As<wstring> ();
    }
}

/*
 ********************************************************************************
 ************************ Transfer::LibCurlException ****************************
 ********************************************************************************
 */
LibCurlException::LibCurlException (CURLcode ccode)
    : StringException (mkExceptMsg_ (ccode))
    , fCurlCode_ (ccode)
{
}

void    LibCurlException::DoThrowIfError (CURLcode status)
{
    if (status != CURLE_OK) {
        DbgTrace (L"In LibCurlException::DoThrowIfError: throwing status %d (%s)", status, LibCurlException (status).As<String> ().c_str ());
        Execution::DoThrow (LibCurlException (status));
    }
}
#endif

#if     qHasFeature_libcurl
/*
 ********************************************************************************
 ****************** Transfer::Connection_LibCurl::Rep_ **************************
 ********************************************************************************
 */
Connection_LibCurl::Rep_::~Rep_ ()
{
    if (fCurlHandle_ != nullptr) {
        curl_easy_cleanup (fCurlHandle_);
    }
    if (fSavedHeaders_ != nullptr) {
        curl_slist_free_all (fSavedHeaders_);
        fSavedHeaders_ = nullptr;
    }
}

DurationSecondsType Connection_LibCurl::Rep_::GetTimeout () const
{
    AssertNotImplemented ();
    return 0;
}

void    Connection_LibCurl::Rep_::SetTimeout (DurationSecondsType timeout)
{
    MakeHandleIfNeeded_ ();
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_TIMEOUT_MS, static_cast<int> (timeout * 1000)));
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CONNECTTIMEOUT_MS, static_cast<int> (timeout * 1000)));
}

URL     Connection_LibCurl::Rep_::GetURL () const
{
    // needs work... - not sure this is safe - may need to cache orig... instead of reparsing...
    return URL::Parse (String::FromUTF8 (fCURLCacheUTF8_URL_).As<wstring> ());
}

void    Connection_LibCurl::Rep_::SetURL (const URL& url)
{
    MakeHandleIfNeeded_ ();
    fCURLCacheUTF8_URL_ = String (url.GetFullURL ()).AsUTF8 ();
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace ("Connection_LibCurl::Rep_::SetURL ('%s')", fCURLCacheUTF8_URL_.c_str ());
#endif
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCacheUTF8_URL_.c_str ()));
}

void    Connection_LibCurl::Rep_::Close ()
{
    if (fCurlHandle_ != nullptr) {
        ::curl_easy_cleanup (fCurlHandle_);
        fCurlHandle_ = nullptr;
    }
}

size_t  Connection_LibCurl::Rep_::s_RequestPayloadReadHandler_ (char* buffer, size_t size, size_t nitems, void* userP)
{
    return reinterpret_cast<Rep_*> (userP)->RequestPayloadReadHandler_ (reinterpret_cast<Byte*> (buffer), size * nitems);
}

size_t  Connection_LibCurl::Rep_::RequestPayloadReadHandler_ (Byte* buffer, size_t bufSize)
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx (SDKSTR ("Connection_LibCurl::Rep_::RequestPayloadReadHandler_"));
#endif
    size_t  bytes2Copy = fUploadData_.size () - fUploadDataCursor_;
    bytes2Copy = min (bytes2Copy, bufSize);
    memcpy (buffer, Traversal::Iterator2Pointer (begin (fUploadData_)) +  fUploadDataCursor_, bytes2Copy);
    fUploadDataCursor_ += bytes2Copy;
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"bufSize = %d, bytes2Copy=%d", bufSize, bytes2Copy);
#endif
    return bytes2Copy;
}

size_t  Connection_LibCurl::Rep_::s_ResponseWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
    return reinterpret_cast<Rep_*> (userP)->ResponseWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t  Connection_LibCurl::Rep_::ResponseWriteHandler_ (const Byte* ptr, size_t nBytes)
{
    fResponseData_.insert (fResponseData_.end (), ptr, ptr + nBytes);
    return nBytes;
}

size_t  Connection_LibCurl::Rep_::s_ResponseHeaderWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
    return reinterpret_cast<Rep_*> (userP)->ResponseHeaderWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t  Connection_LibCurl::Rep_::ResponseHeaderWriteHandler_ (const Byte* ptr, size_t nBytes)
{
    String  from    =   String::FromUTF8 (reinterpret_cast<const char*> (ptr), reinterpret_cast<const char*> (ptr) + nBytes);
    String  to;
    size_t  i       =   from.find (':');
    if (i != string::npos) {
        to = from.SubString (i + 1);
        from = from.SubString (0, i);
    }
    from = from.Trim ();
    to = to.Trim ();
    fResponseHeaders_.Add (from, to);
    return nBytes;
}

Response    Connection_LibCurl::Rep_::Send (const Request& request)
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx (SDKSTR ("Connection_LibCurl::Rep_::Send"));
    DbgTrace (L"(method='%s')", request.fMethod.c_str ());
#endif
    MakeHandleIfNeeded_ ();
    fUploadData_ = request.fData.As<vector<Byte>> ();
    fUploadDataCursor_ = 0;
    fResponseData_.clear ();
    fResponseHeaders_.clear ();

    //grab useragent from request headers...
    //curl_easy_setopt (fCurlHandle_, CURLOPT_USERAGENT, "libcurl-agent/1.0");

    Mapping<String, String>  overrideHeaders = request.fOverrideHeaders;
    if (fOptions.fAssumeLowestCommonDenominatorHTTPServer) {
        static  const   LEGACY_Synchronized<Mapping<String, String>>    kSilenceTheseHeaders_ = initializer_list<pair<String, String>> {
            { String_Constant (L"Expect"), String ()},
            { String_Constant (L"Transfer-Encoding"), String ()}
        };
        overrideHeaders = kSilenceTheseHeaders_ + overrideHeaders;
    }

    if (request.fMethod == HTTP::Methods::kGet) {
        if (not fCURLCacheUTF8_Method_.empty ()) {
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , nullptr));
            fCURLCacheUTF8_Method_.clear ();
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPGET, 1));
    }
    else if (request.fMethod == HTTP::Methods::kPost) {
        if (not fCURLCacheUTF8_Method_.empty ()) {
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , nullptr));
            fCURLCacheUTF8_Method_.clear ();
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_POST, 1));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_POSTFIELDSIZE, fUploadData_.size ()));
    }
    else if (request.fMethod == HTTP::Methods::kPut) {
        if (not fCURLCacheUTF8_Method_.empty ()) {
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , nullptr));
            fCURLCacheUTF8_Method_.clear ();
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_UPLOAD, fUploadData_.empty () ? 0 : 1));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_INFILESIZE , fUploadData_.size ()));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_PUT, 1));
    }
    else {
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPGET, 0));
        if (not fCURLCacheUTF8_Method_.empty ()) {
            fCURLCacheUTF8_Method_ = request.fMethod.AsUTF8 ();
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , fCURLCacheUTF8_Method_.c_str ()));
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , 1));
    }

    // grab initial headers and do POST/etc based on args in request...
    curl_slist* tmpH    =   nullptr;
    for (auto i : overrideHeaders) {
        tmpH = curl_slist_append (tmpH, (i.fKey + String_Constant (L": ") + i.fValue).AsUTF8 ().c_str ());
    }
    AssertNotNull (fCurlHandle_);
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPHEADER, tmpH));
    if (fSavedHeaders_ != nullptr) {
        curl_slist_free_all (fSavedHeaders_);
        fSavedHeaders_ = nullptr;
    }
    fSavedHeaders_ = tmpH;

    LibCurlException::DoThrowIfError (:: curl_easy_perform (fCurlHandle_));

    long    resultCode  =   0;
    LibCurlException::DoThrowIfError (::curl_easy_getinfo (fCurlHandle_, CURLINFO_RESPONSE_CODE, &resultCode));
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"returning status = %d, dataLen = %d", resultCode, fResponseData_.size ());
#endif
    return Response (move (fResponseData_), resultCode, move (fResponseHeaders_));
}

void    Connection_LibCurl::Rep_::MakeHandleIfNeeded_ ()
{
    if (fCurlHandle_ == nullptr) {
        ThrowIfNull (fCurlHandle_ = ::curl_easy_init ());

        /*
         * Now setup COMMON options we ALWAYS set.
         */
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCacheUTF8_URL_.c_str ()));

#if     USE_LIBCURL_VERBOSE_
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_VERBOSE, 1));
#endif

        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_READFUNCTION, s_RequestPayloadReadHandler_));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_READDATA, this));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_WRITEFUNCTION, s_ResponseWriteHandler_));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_WRITEDATA, this));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HEADERFUNCTION, s_ResponseHeaderWriteHandler_));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_WRITEHEADER, this));
    }
}
#endif

#if     qHasFeature_libcurl
/*
 ********************************************************************************
 ********************** Transfer::Connection_LibCurl ****************************
 ********************************************************************************
 */
Connection_LibCurl::Connection_LibCurl (const Options& options)
    : Connection (shared_ptr<_IRep> (new Rep_ (options)))
{
}
#endif
<commit_msg>remove obsolete LEGACY_Synchonized usage<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../../../StroikaPreComp.h"

#if     qHasFeature_libcurl
#include    <curl/curl.h>
#endif

#include    "../../../Characters/Format.h"
#include    "../../../Characters/String_Constant.h"
#include    "../../../Debug/Trace.h"
#include    "../../../Execution/Exceptions.h"

#include    "../HTTP/Methods.h"

#include    "Client_libcurl.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;
using   namespace   Stroika::Foundation::Execution;
using   namespace   Stroika::Foundation::IO;
using   namespace   Stroika::Foundation::IO::Network;
using   namespace   Stroika::Foundation::IO::Network::Transfer;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

// Uncomment this line to enable libcurl to print diagnostics to stderr
//#define       USE_LIBCURL_VERBOSE_    1

#if     qHasFeature_libcurl
namespace   {
    struct  ModuleInit_ {
        ModuleInit_ ()
        {
            ::curl_global_init (CURL_GLOBAL_ALL);
        }
    };
    ModuleInit_ sIniter_;
}
#endif

#if     qHasFeature_libcurl
class   Connection_LibCurl::Rep_ : public _IRep {
public:
    Connection::Options fOptions;

public:
    Rep_ (const Connection::Options& options)
        : fOptions (options)
    {
    }
    Rep_ (const Rep_&) = delete;
    virtual ~Rep_ ();

public:
    nonvirtual  Rep_& operator= (const Rep_&) = delete;

public:
    virtual DurationSecondsType GetTimeout () const override;
    virtual void                SetTimeout (DurationSecondsType timeout) override;
    virtual URL                 GetURL () const override;
    virtual void                SetURL (const URL& url) override;
    virtual void                Close ()    override;
    virtual Response            Send (const Request& request) override;

private:
    nonvirtual  void    MakeHandleIfNeeded_ ();

private:
    static      size_t  s_RequestPayloadReadHandler_ (char* buffer, size_t size, size_t nitems, void* userP);
    nonvirtual  size_t  RequestPayloadReadHandler_ (Byte* buffer, size_t bufSize);

private:
    static      size_t  s_ResponseWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP);
    nonvirtual  size_t  ResponseWriteHandler_ (const Byte* ptr, size_t nBytes);

private:
    static      size_t  s_ResponseHeaderWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP);
    nonvirtual  size_t  ResponseHeaderWriteHandler_ (const Byte* ptr, size_t nBytes);

private:
    void*                   fCurlHandle_ { nullptr };
    string                  fCURLCacheUTF8_URL_;    // cuz of quirky memory management policies of libcurl
    string                  fCURLCacheUTF8_Method_;     // cuz of quirky memory management policies of libcurl
    vector<Byte>            fUploadData_;
    size_t                  fUploadDataCursor_ {};
    vector<Byte>            fResponseData_;
    Mapping<String, String> fResponseHeaders_;
    curl_slist*             fSavedHeaders_ { nullptr };
};
#endif

#if     qHasFeature_libcurl
namespace   {
    wstring mkExceptMsg_ (LibCurlException::CURLcode ccode)
    {
        return String::FromUTF8 (curl_easy_strerror (static_cast<CURLcode> (ccode))).As<wstring> ();
    }
}

/*
 ********************************************************************************
 ************************ Transfer::LibCurlException ****************************
 ********************************************************************************
 */
LibCurlException::LibCurlException (CURLcode ccode)
    : StringException (mkExceptMsg_ (ccode))
    , fCurlCode_ (ccode)
{
}

void    LibCurlException::DoThrowIfError (CURLcode status)
{
    if (status != CURLE_OK) {
        DbgTrace (L"In LibCurlException::DoThrowIfError: throwing status %d (%s)", status, LibCurlException (status).As<String> ().c_str ());
        Execution::DoThrow (LibCurlException (status));
    }
}
#endif

#if     qHasFeature_libcurl
/*
 ********************************************************************************
 ****************** Transfer::Connection_LibCurl::Rep_ **************************
 ********************************************************************************
 */
Connection_LibCurl::Rep_::~Rep_ ()
{
    if (fCurlHandle_ != nullptr) {
        curl_easy_cleanup (fCurlHandle_);
    }
    if (fSavedHeaders_ != nullptr) {
        curl_slist_free_all (fSavedHeaders_);
        fSavedHeaders_ = nullptr;
    }
}

DurationSecondsType Connection_LibCurl::Rep_::GetTimeout () const
{
    AssertNotImplemented ();
    return 0;
}

void    Connection_LibCurl::Rep_::SetTimeout (DurationSecondsType timeout)
{
    MakeHandleIfNeeded_ ();
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_TIMEOUT_MS, static_cast<int> (timeout * 1000)));
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CONNECTTIMEOUT_MS, static_cast<int> (timeout * 1000)));
}

URL     Connection_LibCurl::Rep_::GetURL () const
{
    // needs work... - not sure this is safe - may need to cache orig... instead of reparsing...
    return URL::Parse (String::FromUTF8 (fCURLCacheUTF8_URL_).As<wstring> ());
}

void    Connection_LibCurl::Rep_::SetURL (const URL& url)
{
    MakeHandleIfNeeded_ ();
    fCURLCacheUTF8_URL_ = String (url.GetFullURL ()).AsUTF8 ();
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace ("Connection_LibCurl::Rep_::SetURL ('%s')", fCURLCacheUTF8_URL_.c_str ());
#endif
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCacheUTF8_URL_.c_str ()));
}

void    Connection_LibCurl::Rep_::Close ()
{
    if (fCurlHandle_ != nullptr) {
        ::curl_easy_cleanup (fCurlHandle_);
        fCurlHandle_ = nullptr;
    }
}

size_t  Connection_LibCurl::Rep_::s_RequestPayloadReadHandler_ (char* buffer, size_t size, size_t nitems, void* userP)
{
    return reinterpret_cast<Rep_*> (userP)->RequestPayloadReadHandler_ (reinterpret_cast<Byte*> (buffer), size * nitems);
}

size_t  Connection_LibCurl::Rep_::RequestPayloadReadHandler_ (Byte* buffer, size_t bufSize)
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx (SDKSTR ("Connection_LibCurl::Rep_::RequestPayloadReadHandler_"));
#endif
    size_t  bytes2Copy = fUploadData_.size () - fUploadDataCursor_;
    bytes2Copy = min (bytes2Copy, bufSize);
    memcpy (buffer, Traversal::Iterator2Pointer (begin (fUploadData_)) +  fUploadDataCursor_, bytes2Copy);
    fUploadDataCursor_ += bytes2Copy;
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"bufSize = %d, bytes2Copy=%d", bufSize, bytes2Copy);
#endif
    return bytes2Copy;
}

size_t  Connection_LibCurl::Rep_::s_ResponseWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
    return reinterpret_cast<Rep_*> (userP)->ResponseWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t  Connection_LibCurl::Rep_::ResponseWriteHandler_ (const Byte* ptr, size_t nBytes)
{
    fResponseData_.insert (fResponseData_.end (), ptr, ptr + nBytes);
    return nBytes;
}

size_t  Connection_LibCurl::Rep_::s_ResponseHeaderWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
    return reinterpret_cast<Rep_*> (userP)->ResponseHeaderWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t  Connection_LibCurl::Rep_::ResponseHeaderWriteHandler_ (const Byte* ptr, size_t nBytes)
{
    String  from    =   String::FromUTF8 (reinterpret_cast<const char*> (ptr), reinterpret_cast<const char*> (ptr) + nBytes);
    String  to;
    size_t  i       =   from.find (':');
    if (i != string::npos) {
        to = from.SubString (i + 1);
        from = from.SubString (0, i);
    }
    from = from.Trim ();
    to = to.Trim ();
    fResponseHeaders_.Add (from, to);
    return nBytes;
}

Response    Connection_LibCurl::Rep_::Send (const Request& request)
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx (SDKSTR ("Connection_LibCurl::Rep_::Send"));
    DbgTrace (L"(method='%s')", request.fMethod.c_str ());
#endif
    MakeHandleIfNeeded_ ();
    fUploadData_ = request.fData.As<vector<Byte>> ();
    fUploadDataCursor_ = 0;
    fResponseData_.clear ();
    fResponseHeaders_.clear ();

    //grab useragent from request headers...
    //curl_easy_setopt (fCurlHandle_, CURLOPT_USERAGENT, "libcurl-agent/1.0");

    Mapping<String, String>  overrideHeaders = request.fOverrideHeaders;
    if (fOptions.fAssumeLowestCommonDenominatorHTTPServer) {
        // @todo CONSIDER if we need to use Synchonized<> here. At one point we did, but perhaps no longer?
        // --LGP 2015-01-10
        static  const   Mapping<String, String>    kSilenceTheseHeaders_  {{
                { String_Constant (L"Expect"), String ()},
                { String_Constant (L"Transfer-Encoding"), String ()}
            }
        };
        overrideHeaders = kSilenceTheseHeaders_ + overrideHeaders;
    }

    if (request.fMethod == HTTP::Methods::kGet) {
        if (not fCURLCacheUTF8_Method_.empty ()) {
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , nullptr));
            fCURLCacheUTF8_Method_.clear ();
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPGET, 1));
    }
    else if (request.fMethod == HTTP::Methods::kPost) {
        if (not fCURLCacheUTF8_Method_.empty ()) {
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , nullptr));
            fCURLCacheUTF8_Method_.clear ();
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_POST, 1));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_POSTFIELDSIZE, fUploadData_.size ()));
    }
    else if (request.fMethod == HTTP::Methods::kPut) {
        if (not fCURLCacheUTF8_Method_.empty ()) {
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , nullptr));
            fCURLCacheUTF8_Method_.clear ();
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_UPLOAD, fUploadData_.empty () ? 0 : 1));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_INFILESIZE , fUploadData_.size ()));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_PUT, 1));
    }
    else {
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPGET, 0));
        if (not fCURLCacheUTF8_Method_.empty ()) {
            fCURLCacheUTF8_Method_ = request.fMethod.AsUTF8 ();
            LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , fCURLCacheUTF8_Method_.c_str ()));
        }
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_CUSTOMREQUEST , 1));
    }

    // grab initial headers and do POST/etc based on args in request...
    curl_slist* tmpH    =   nullptr;
    for (auto i : overrideHeaders) {
        tmpH = curl_slist_append (tmpH, (i.fKey + String_Constant (L": ") + i.fValue).AsUTF8 ().c_str ());
    }
    AssertNotNull (fCurlHandle_);
    LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPHEADER, tmpH));
    if (fSavedHeaders_ != nullptr) {
        curl_slist_free_all (fSavedHeaders_);
        fSavedHeaders_ = nullptr;
    }
    fSavedHeaders_ = tmpH;

    LibCurlException::DoThrowIfError (:: curl_easy_perform (fCurlHandle_));

    long    resultCode  =   0;
    LibCurlException::DoThrowIfError (::curl_easy_getinfo (fCurlHandle_, CURLINFO_RESPONSE_CODE, &resultCode));
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"returning status = %d, dataLen = %d", resultCode, fResponseData_.size ());
#endif
    return Response (move (fResponseData_), resultCode, move (fResponseHeaders_));
}

void    Connection_LibCurl::Rep_::MakeHandleIfNeeded_ ()
{
    if (fCurlHandle_ == nullptr) {
        ThrowIfNull (fCurlHandle_ = ::curl_easy_init ());

        /*
         * Now setup COMMON options we ALWAYS set.
         */
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCacheUTF8_URL_.c_str ()));

#if     USE_LIBCURL_VERBOSE_
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_VERBOSE, 1));
#endif

        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_READFUNCTION, s_RequestPayloadReadHandler_));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_READDATA, this));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_WRITEFUNCTION, s_ResponseWriteHandler_));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_WRITEDATA, this));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HEADERFUNCTION, s_ResponseHeaderWriteHandler_));
        LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_WRITEHEADER, this));
    }
}
#endif

#if     qHasFeature_libcurl
/*
 ********************************************************************************
 ********************** Transfer::Connection_LibCurl ****************************
 ********************************************************************************
 */
Connection_LibCurl::Connection_LibCurl (const Options& options)
    : Connection (shared_ptr<_IRep> (new Rep_ (options)))
{
}
#endif
<|endoftext|>


<commit_before>/*********************************
** Tsunagari Tile Engine        **
** area.cpp                     **
** Copyright 2011-2012 OmegaSDG **
*********************************/

#include <algorithm>
#include <math.h>
#include <vector>

#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <Gosu/Graphics.hpp>
#include <Gosu/Image.hpp>
#include <Gosu/Math.hpp>
#include <Gosu/Timing.hpp>

#include "area.h"
#include "common.h"
#include "entity.h"
#include "log.h"
#include "python.h"
#include "resourcer.h"
#include "tile.h"
#include "window.h"
#include "world.h"

#define ASSERT(x)  if (!(x)) return false

/* NOTE: In the TMX map format used by Tiled, tileset tiles start counting
         their Y-positions from 0, while layer tiles start counting from 1. I
         can't imagine why the author did this, but we have to take it into
         account.
*/

Area::Area(Viewport* view,
           Player* player,
           Music* music,
           const std::string& descriptor)
	: view(view),
	  player(player),
	  music(music),
	  colorOverlay(0, 0, 0, 0),
	  dim(0, 0, 0),
	  tileDim(0, 0),
	  loopX(false), loopY(false),
	  beenFocused(false),
	  redraw(true),
	  descriptor(descriptor)
{
}

Area::~Area()
{
}

bool Area::init()
{
	// Abstract method.
	return false;
}

void Area::focus()
{
	if (!beenFocused) {
		beenFocused = true;
		runOnLoads();
	}

	music->setIntro(musicIntro);
	music->setLoop(musicLoop);

	if (onFocusScripts.size()) {
		BOOST_FOREACH(const std::string& script, onFocusScripts) {
			pythonSetGlobal("Area", this);
			Resourcer* rc = Resourcer::instance();
			rc->runPythonScript(script);
		}
	}
}

void Area::buttonDown(const Gosu::Button btn)
{
	if (btn == Gosu::kbRight)
		player->startMovement(ivec2(1, 0));
	else if (btn == Gosu::kbLeft)
		player->startMovement(ivec2(-1, 0));
	else if (btn == Gosu::kbUp)
		player->startMovement(ivec2(0, -1));
	else if (btn == Gosu::kbDown)
		player->startMovement(ivec2(0, 1));
	else if (btn == Gosu::kbSpace)
		player->useTile();
}

void Area::buttonUp(const Gosu::Button btn)
{
	if (btn == Gosu::kbRight)
		player->stopMovement(ivec2(1, 0));
	else if (btn == Gosu::kbLeft)
		player->stopMovement(ivec2(-1, 0));
	else if (btn == Gosu::kbUp)
		player->stopMovement(ivec2(0, -1));
	else if (btn == Gosu::kbDown)
		player->stopMovement(ivec2(0, 1));
}

void Area::draw()
{
	updateTileAnimations();
	drawTiles();
	drawEntities();
	drawColorOverlay();
	redraw = false;
}

bool Area::needsRedraw() const
{
	if (redraw)
		return true;
	if (player->needsRedraw())
		return true;

	// Do any on-screen tile types need to update their animations?
	const icube_t tiles = visibleTiles();
	for (int z = tiles.z1; z < tiles.z2; z++) {
		for (int y = tiles.y1; y < tiles.y2; y++) {
			for (int x = tiles.x1; x < tiles.x2; x++) {
				const Tile& tile = getTile(x, y, z);
				const TileType* type = tile.getType();
				if (type && type->needsRedraw())
					return true;
			}
		}
	}
	return false;
}

void Area::requestRedraw()
{
	redraw = true;
}

void Area::update(unsigned long dt)
{
	pythonSetGlobal("Area", this);
	player->update(dt);

	if (onUpdateScripts.size()) {
		BOOST_FOREACH(const std::string& script, onUpdateScripts) {
			pythonSetGlobal("Area", this);
			Resourcer* rc = Resourcer::instance();
			rc->runPythonScript(script);
		}
	}

	view->update(dt);
	music->update();
}

AreaPtr Area::reset()
{
	World* world = World::instance();
	AreaPtr newSelf = world->getArea(descriptor, GETAREA_ALWAYS_CREATE);
	if (world->getFocusedArea().get() == this) {
		vicoord c = player->getTileCoords_vi();
		world->focusArea(newSelf, c);
	}
	return newSelf;
}

void Area::setColorOverlay(int r, int g, int b, int a)
{
	using namespace Gosu;

	if (0 <= r && r < 256 &&
	    0 <= g && g < 256 &&
	    0 <= b && b < 256 &&
	    0 <= a && a < 256) {
		Color::Channel ac = (Color::Channel)a;
		Color::Channel rc = (Color::Channel)r;
		Color::Channel gc = (Color::Channel)g;
		Color::Channel bc = (Color::Channel)b;
		colorOverlay = Color(ac, rc, gc, bc);
		redraw = true;
	}
	else {
		PyErr_Format(PyExc_ValueError,
			"Area::color_overlay() arguments must be "
			"between 0 and 255");
	}
}

const Tile& Area::getTile(int x, int y, int z) const
{
	if (loopX)
		x = wrap(0, x, dim.x);
	if (loopY)
		y = wrap(0, y, dim.y);
	return map[z][y][x];
}

const Tile& Area::getTile(int x, int y, double z) const
{
	return getTile(x, y, depthIndex(z));
}

const Tile& Area::getTile(icoord phys) const
{
	return getTile(phys.x, phys.y, phys.z);
}

const Tile& Area::getTile(vicoord virt) const
{
	return getTile(virt2phys(virt));
}

Tile& Area::getTile(int x, int y, int z)
{
	if (loopX)
		x = wrap(0, x, dim.x);
	if (loopY)
		y = wrap(0, y, dim.y);
	return map[z][y][x];
}

Tile& Area::getTile(int x, int y, double z)
{
	return getTile(x, y, depthIndex(z));
}

Tile& Area::getTile(icoord phys)
{
	return getTile(phys.x, phys.y, phys.z);
}

Tile& Area::getTile(vicoord virt)
{
	return getTile(virt2phys(virt));
}

TileType& Area::getTileType(int idx)
{
	return tileTypes[idx];
}

ivec3 Area::getDimensions() const
{
	return dim;
}

ivec2 Area::getTileDimensions() const
{
	return tileDim;
}

icube_t Area::visibleTileBounds() const
{
	rvec2 screen = view->getVirtRes();
	rvec2 off = view->getMapOffset();

	int x1 = (int)floor(off.x / tileDim.x);
	int y1 = (int)floor(off.y / tileDim.y);
	int x2 = (int)ceil((screen.x + off.x) / tileDim.x);
	int y2 = (int)ceil((screen.y + off.y) / tileDim.y);

	return icube(x1, y1, 0, x2, y2, dim.z);
}

icube_t Area::visibleTiles() const
{
	icube_t cube = visibleTileBounds();
	if (!loopX) {
		cube.x1 = std::max(cube.x1, 0);
		cube.x2 = std::min(cube.x2, dim.x);
	}
	if (!loopY) {
		cube.y1 = std::max(cube.y1, 0);
		cube.y2 = std::min(cube.y2, dim.y);
	}
	return cube;
}

bool Area::inBounds(int x, int y, int z) const
{
	return ((loopX || (0 <= x && x < dim.x)) &&
		(loopY || (0 <= y && y < dim.y)) &&
		          0 <= z && z < dim.z);
}

bool Area::inBounds(int x, int y, double z) const
{
	return inBounds(x, y, depthIndex(z));
}

bool Area::inBounds(icoord phys) const
{
	return inBounds(phys.x, phys.y, phys.z);
}

bool Area::inBounds(vicoord virt) const
{
	return inBounds(virt2phys(virt));
}

bool Area::loopsInX() const
{
	return loopX;
}

bool Area::loopsInY() const
{
	return loopY;
}

const std::string Area::getDescriptor() const
{
	return descriptor;
}

vicoord Area::phys2virt_vi(icoord phys) const
{
	return vicoord(phys.x, phys.y, indexDepth(phys.z));
}

rcoord Area::phys2virt_r(icoord phys) const
{
	return rcoord(
		(double)phys.x * tileDim.x,
		(double)phys.y * tileDim.y,
		indexDepth(phys.z)
	);
}

icoord Area::virt2phys(vicoord virt) const
{
	return icoord(virt.x, virt.y, depthIndex(virt.z));
}

icoord Area::virt2phys(rcoord virt) const
{
	return icoord(
		(int)(virt.x / tileDim.x),
		(int)(virt.y / tileDim.y),
		depthIndex(virt.z)
	);
}

rcoord Area::virt2virt(vicoord virt) const
{
	return rcoord(
		(double)virt.x * tileDim.x,
		(double)virt.y * tileDim.y,
		virt.z
	);
}

vicoord Area::virt2virt(rcoord virt) const
{
	return vicoord(
		(int)virt.x / tileDim.x,
		(int)virt.y / tileDim.y,
		virt.z
	);
}

int Area::depthIndex(double depth) const
{
	return depth2idx.find(depth)->second;
}

double Area::indexDepth(int idx) const
{
	return idx2depth[idx];
}

void Area::runOnLoads()
{
	Resourcer* rc = Resourcer::instance();
	World* world = World::instance();
	std::string onAreaLoadScript = world->getAreaLoadScript();
	if (onAreaLoadScript.size()) {
		pythonSetGlobal("Area", this);
		rc->runPythonScript(onAreaLoadScript);
	}
	BOOST_FOREACH(const std::string& script, onLoadScripts) {
		pythonSetGlobal("Area", this);
		rc->runPythonScript(script);
	}
}

void Area::updateTileAnimations()
{
	const int millis = GameWindow::instance().time();
	BOOST_FOREACH(TileType& type, tileTypes)
		type.anim.updateFrame(millis);
}

void Area::drawTiles() const
{
	const icube_t tiles = visibleTiles();
	for (int z = tiles.z1; z < tiles.z2; z++) {
		double depth = idx2depth[z];
		for (int y = tiles.y1; y < tiles.y2; y++) {
			for (int x = tiles.x1; x < tiles.x2; x++) {
				const Tile& tile = getTile(x, y, z);
				drawTile(tile, x, y, depth);
			}
		}
	}
}

void Area::drawTile(const Tile& tile, int x, int y, double depth) const
{
	const TileType* type = (TileType*)tile.parent;
	if (type) {
		const Gosu::Image* img = type->anim.frame();
		if (img)
			img->draw((double)x*img->width(),
				  (double)y*img->height(), depth);
	}
}

void Area::drawEntities()
{
	player->draw();
}

void Area::drawColorOverlay()
{
	if (colorOverlay.alpha() != 0) {
		GameWindow& window = GameWindow::instance();
		Gosu::Color c = colorOverlay;
		int x = window.width();
		int y = window.height();
		window.graphics().drawQuad(
			0, 0, c,
			x, 0, c,
			x, y, c,
			0, y, c,
			750
		);
	}
}

boost::python::tuple Area::pyGetDimensions()
{
	using namespace boost::python;

	list zs;
	BOOST_FOREACH(double dep, idx2depth) {
		zs.append(dep);
	}
	return boost::python::make_tuple(dim.x, dim.y, zs);
}

void exportArea()
{
	boost::python::class_<Area>("Area", boost::python::no_init)
		.add_property("descriptor", &Area::getDescriptor)
		.add_property("dimensions", &Area::pyGetDimensions)
		.def("request_redraw", &Area::requestRedraw)
		.def("tiles",
		    static_cast<Tile& (Area::*) (int, int, double)>
		    (&Area::getTile),
		    boost::python::return_value_policy<
		      boost::python::reference_existing_object
		    >())
		.def("in_bounds",
		    static_cast<bool (Area::*) (int, int, double) const>
		    (&Area::inBounds))
		.def("get_tile_type", &Area::getTileType,
		    boost::python::return_value_policy<
		      boost::python::reference_existing_object
		    >()
		)
		.def("reset", &Area::reset)
		.def("color_overlay", &Area::setColorOverlay)
		;
}

<commit_msg>cleanup exportArea<commit_after>/*********************************
** Tsunagari Tile Engine        **
** area.cpp                     **
** Copyright 2011-2012 OmegaSDG **
*********************************/

#include <algorithm>
#include <math.h>
#include <vector>

#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <Gosu/Graphics.hpp>
#include <Gosu/Image.hpp>
#include <Gosu/Math.hpp>
#include <Gosu/Timing.hpp>

#include "area.h"
#include "common.h"
#include "entity.h"
#include "log.h"
#include "python.h"
#include "resourcer.h"
#include "tile.h"
#include "window.h"
#include "world.h"

#define ASSERT(x)  if (!(x)) return false

/* NOTE: In the TMX map format used by Tiled, tileset tiles start counting
         their Y-positions from 0, while layer tiles start counting from 1. I
         can't imagine why the author did this, but we have to take it into
         account.
*/

Area::Area(Viewport* view,
           Player* player,
           Music* music,
           const std::string& descriptor)
	: view(view),
	  player(player),
	  music(music),
	  colorOverlay(0, 0, 0, 0),
	  dim(0, 0, 0),
	  tileDim(0, 0),
	  loopX(false), loopY(false),
	  beenFocused(false),
	  redraw(true),
	  descriptor(descriptor)
{
}

Area::~Area()
{
}

bool Area::init()
{
	// Abstract method.
	return false;
}

void Area::focus()
{
	if (!beenFocused) {
		beenFocused = true;
		runOnLoads();
	}

	music->setIntro(musicIntro);
	music->setLoop(musicLoop);

	if (onFocusScripts.size()) {
		BOOST_FOREACH(const std::string& script, onFocusScripts) {
			pythonSetGlobal("Area", this);
			Resourcer* rc = Resourcer::instance();
			rc->runPythonScript(script);
		}
	}
}

void Area::buttonDown(const Gosu::Button btn)
{
	if (btn == Gosu::kbRight)
		player->startMovement(ivec2(1, 0));
	else if (btn == Gosu::kbLeft)
		player->startMovement(ivec2(-1, 0));
	else if (btn == Gosu::kbUp)
		player->startMovement(ivec2(0, -1));
	else if (btn == Gosu::kbDown)
		player->startMovement(ivec2(0, 1));
	else if (btn == Gosu::kbSpace)
		player->useTile();
}

void Area::buttonUp(const Gosu::Button btn)
{
	if (btn == Gosu::kbRight)
		player->stopMovement(ivec2(1, 0));
	else if (btn == Gosu::kbLeft)
		player->stopMovement(ivec2(-1, 0));
	else if (btn == Gosu::kbUp)
		player->stopMovement(ivec2(0, -1));
	else if (btn == Gosu::kbDown)
		player->stopMovement(ivec2(0, 1));
}

void Area::draw()
{
	updateTileAnimations();
	drawTiles();
	drawEntities();
	drawColorOverlay();
	redraw = false;
}

bool Area::needsRedraw() const
{
	if (redraw)
		return true;
	if (player->needsRedraw())
		return true;

	// Do any on-screen tile types need to update their animations?
	const icube_t tiles = visibleTiles();
	for (int z = tiles.z1; z < tiles.z2; z++) {
		for (int y = tiles.y1; y < tiles.y2; y++) {
			for (int x = tiles.x1; x < tiles.x2; x++) {
				const Tile& tile = getTile(x, y, z);
				const TileType* type = tile.getType();
				if (type && type->needsRedraw())
					return true;
			}
		}
	}
	return false;
}

void Area::requestRedraw()
{
	redraw = true;
}

void Area::update(unsigned long dt)
{
	pythonSetGlobal("Area", this);
	player->update(dt);

	if (onUpdateScripts.size()) {
		BOOST_FOREACH(const std::string& script, onUpdateScripts) {
			pythonSetGlobal("Area", this);
			Resourcer* rc = Resourcer::instance();
			rc->runPythonScript(script);
		}
	}

	view->update(dt);
	music->update();
}

AreaPtr Area::reset()
{
	World* world = World::instance();
	AreaPtr newSelf = world->getArea(descriptor, GETAREA_ALWAYS_CREATE);
	if (world->getFocusedArea().get() == this) {
		vicoord c = player->getTileCoords_vi();
		world->focusArea(newSelf, c);
	}
	return newSelf;
}

void Area::setColorOverlay(int r, int g, int b, int a)
{
	using namespace Gosu;

	if (0 <= r && r < 256 &&
	    0 <= g && g < 256 &&
	    0 <= b && b < 256 &&
	    0 <= a && a < 256) {
		Color::Channel ac = (Color::Channel)a;
		Color::Channel rc = (Color::Channel)r;
		Color::Channel gc = (Color::Channel)g;
		Color::Channel bc = (Color::Channel)b;
		colorOverlay = Color(ac, rc, gc, bc);
		redraw = true;
	}
	else {
		PyErr_Format(PyExc_ValueError,
			"Area::color_overlay() arguments must be "
			"between 0 and 255");
	}
}

const Tile& Area::getTile(int x, int y, int z) const
{
	if (loopX)
		x = wrap(0, x, dim.x);
	if (loopY)
		y = wrap(0, y, dim.y);
	return map[z][y][x];
}

const Tile& Area::getTile(int x, int y, double z) const
{
	return getTile(x, y, depthIndex(z));
}

const Tile& Area::getTile(icoord phys) const
{
	return getTile(phys.x, phys.y, phys.z);
}

const Tile& Area::getTile(vicoord virt) const
{
	return getTile(virt2phys(virt));
}

Tile& Area::getTile(int x, int y, int z)
{
	if (loopX)
		x = wrap(0, x, dim.x);
	if (loopY)
		y = wrap(0, y, dim.y);
	return map[z][y][x];
}

Tile& Area::getTile(int x, int y, double z)
{
	return getTile(x, y, depthIndex(z));
}

Tile& Area::getTile(icoord phys)
{
	return getTile(phys.x, phys.y, phys.z);
}

Tile& Area::getTile(vicoord virt)
{
	return getTile(virt2phys(virt));
}

TileType& Area::getTileType(int idx)
{
	return tileTypes[idx];
}

ivec3 Area::getDimensions() const
{
	return dim;
}

ivec2 Area::getTileDimensions() const
{
	return tileDim;
}

icube_t Area::visibleTileBounds() const
{
	rvec2 screen = view->getVirtRes();
	rvec2 off = view->getMapOffset();

	int x1 = (int)floor(off.x / tileDim.x);
	int y1 = (int)floor(off.y / tileDim.y);
	int x2 = (int)ceil((screen.x + off.x) / tileDim.x);
	int y2 = (int)ceil((screen.y + off.y) / tileDim.y);

	return icube(x1, y1, 0, x2, y2, dim.z);
}

icube_t Area::visibleTiles() const
{
	icube_t cube = visibleTileBounds();
	if (!loopX) {
		cube.x1 = std::max(cube.x1, 0);
		cube.x2 = std::min(cube.x2, dim.x);
	}
	if (!loopY) {
		cube.y1 = std::max(cube.y1, 0);
		cube.y2 = std::min(cube.y2, dim.y);
	}
	return cube;
}

bool Area::inBounds(int x, int y, int z) const
{
	return ((loopX || (0 <= x && x < dim.x)) &&
		(loopY || (0 <= y && y < dim.y)) &&
		          0 <= z && z < dim.z);
}

bool Area::inBounds(int x, int y, double z) const
{
	return inBounds(x, y, depthIndex(z));
}

bool Area::inBounds(icoord phys) const
{
	return inBounds(phys.x, phys.y, phys.z);
}

bool Area::inBounds(vicoord virt) const
{
	return inBounds(virt2phys(virt));
}

bool Area::loopsInX() const
{
	return loopX;
}

bool Area::loopsInY() const
{
	return loopY;
}

const std::string Area::getDescriptor() const
{
	return descriptor;
}

vicoord Area::phys2virt_vi(icoord phys) const
{
	return vicoord(phys.x, phys.y, indexDepth(phys.z));
}

rcoord Area::phys2virt_r(icoord phys) const
{
	return rcoord(
		(double)phys.x * tileDim.x,
		(double)phys.y * tileDim.y,
		indexDepth(phys.z)
	);
}

icoord Area::virt2phys(vicoord virt) const
{
	return icoord(virt.x, virt.y, depthIndex(virt.z));
}

icoord Area::virt2phys(rcoord virt) const
{
	return icoord(
		(int)(virt.x / tileDim.x),
		(int)(virt.y / tileDim.y),
		depthIndex(virt.z)
	);
}

rcoord Area::virt2virt(vicoord virt) const
{
	return rcoord(
		(double)virt.x * tileDim.x,
		(double)virt.y * tileDim.y,
		virt.z
	);
}

vicoord Area::virt2virt(rcoord virt) const
{
	return vicoord(
		(int)virt.x / tileDim.x,
		(int)virt.y / tileDim.y,
		virt.z
	);
}

int Area::depthIndex(double depth) const
{
	return depth2idx.find(depth)->second;
}

double Area::indexDepth(int idx) const
{
	return idx2depth[idx];
}

void Area::runOnLoads()
{
	Resourcer* rc = Resourcer::instance();
	World* world = World::instance();
	std::string onAreaLoadScript = world->getAreaLoadScript();
	if (onAreaLoadScript.size()) {
		pythonSetGlobal("Area", this);
		rc->runPythonScript(onAreaLoadScript);
	}
	BOOST_FOREACH(const std::string& script, onLoadScripts) {
		pythonSetGlobal("Area", this);
		rc->runPythonScript(script);
	}
}

void Area::updateTileAnimations()
{
	const int millis = GameWindow::instance().time();
	BOOST_FOREACH(TileType& type, tileTypes)
		type.anim.updateFrame(millis);
}

void Area::drawTiles() const
{
	const icube_t tiles = visibleTiles();
	for (int z = tiles.z1; z < tiles.z2; z++) {
		double depth = idx2depth[z];
		for (int y = tiles.y1; y < tiles.y2; y++) {
			for (int x = tiles.x1; x < tiles.x2; x++) {
				const Tile& tile = getTile(x, y, z);
				drawTile(tile, x, y, depth);
			}
		}
	}
}

void Area::drawTile(const Tile& tile, int x, int y, double depth) const
{
	const TileType* type = (TileType*)tile.parent;
	if (type) {
		const Gosu::Image* img = type->anim.frame();
		if (img)
			img->draw((double)x*img->width(),
				  (double)y*img->height(), depth);
	}
}

void Area::drawEntities()
{
	player->draw();
}

void Area::drawColorOverlay()
{
	if (colorOverlay.alpha() != 0) {
		GameWindow& window = GameWindow::instance();
		Gosu::Color c = colorOverlay;
		int x = window.width();
		int y = window.height();
		window.graphics().drawQuad(
			0, 0, c,
			x, 0, c,
			x, y, c,
			0, y, c,
			750
		);
	}
}

boost::python::tuple Area::pyGetDimensions()
{
	using namespace boost::python;

	list zs;
	BOOST_FOREACH(double dep, idx2depth)
		zs.append(dep);
	return make_tuple(dim.x, dim.y, zs);
}

void exportArea()
{
	using namespace boost::python;

	class_<Area>("Area", no_init)
		.add_property("descriptor", &Area::getDescriptor)
		.add_property("dimensions", &Area::pyGetDimensions)
		.def("request_redraw", &Area::requestRedraw)
		.def("tiles",
		    static_cast<Tile& (Area::*) (int, int, double)>
		    (&Area::getTile),
		    return_value_policy<reference_existing_object>())
		.def("in_bounds",
		    static_cast<bool (Area::*) (int, int, double) const>
		    (&Area::inBounds))
		.def("get_tile_type", &Area::getTileType,
		    return_value_policy<reference_existing_object>())
		.def("reset", &Area::reset)
		.def("color_overlay", &Area::setColorOverlay)
		;
}

<|endoftext|>


<commit_before>// builds all boost.asio source as a separate compilation unit
#include <boost/version.hpp>

#ifndef BOOST_ASIO_SOURCE
#define BOOST_ASIO_SOURCE
#endif

#ifdef _MSC_VER

// on windows; including timer_queue.hpp results in an
// actual link-time dependency on boost.date_time, even
// though it's never referenced. So, avoid that on windows.
// on Mac OS X and Linux, not including it results in
// missing symbols. For some reason, this current setup
// works, at least across windows, Linux and Mac OS X.
// In the future this hack can be fixed by disabling
// use of boost.date_time in boost.asio

#include <boost/asio/detail/config.hpp>

#if defined(BOOST_ASIO_HEADER_ONLY)
# error Do not compile Asio library source with BOOST_ASIO_HEADER_ONLY defined
#endif

#include <boost/asio/impl/error.ipp>
#include <boost/asio/impl/io_service.ipp>
#include <boost/asio/impl/serial_port_base.ipp>
#include <boost/asio/detail/impl/descriptor_ops.ipp>
#include <boost/asio/detail/impl/dev_poll_reactor.ipp>
#include <boost/asio/detail/impl/epoll_reactor.ipp>
#include <boost/asio/detail/impl/eventfd_select_interrupter.ipp>
#if BOOST_VERSION >= 104700
#include <boost/asio/detail/impl/handler_tracking.ipp>
#include <boost/asio/detail/impl/signal_set_service.ipp>
#include <boost/asio/detail/impl/win_static_mutex.ipp>
#endif
#include <boost/asio/detail/impl/kqueue_reactor.ipp>
#include <boost/asio/detail/impl/pipe_select_interrupter.ipp>
#include <boost/asio/detail/impl/posix_event.ipp>
#include <boost/asio/detail/impl/posix_mutex.ipp>
#include <boost/asio/detail/impl/posix_thread.ipp>
#include <boost/asio/detail/impl/posix_tss_ptr.ipp>
#include <boost/asio/detail/impl/reactive_descriptor_service.ipp>
#include <boost/asio/detail/impl/reactive_serial_port_service.ipp>
#include <boost/asio/detail/impl/reactive_socket_service_base.ipp>
#include <boost/asio/detail/impl/resolver_service_base.ipp>
#include <boost/asio/detail/impl/select_reactor.ipp>
#include <boost/asio/detail/impl/service_registry.ipp>
#include <boost/asio/detail/impl/socket_ops.ipp>
#include <boost/asio/detail/impl/socket_select_interrupter.ipp>
#include <boost/asio/detail/impl/strand_service.ipp>
#include <boost/asio/detail/impl/task_io_service.ipp>
#include <boost/asio/detail/impl/throw_error.ipp>
//#include <boost/asio/detail/impl/timer_queue.ipp>
#include <boost/asio/detail/impl/timer_queue_set.ipp>
#include <boost/asio/detail/impl/win_iocp_handle_service.ipp>
#include <boost/asio/detail/impl/win_iocp_io_service.ipp>
#include <boost/asio/detail/impl/win_iocp_serial_port_service.ipp>
#include <boost/asio/detail/impl/win_iocp_socket_service_base.ipp>
#include <boost/asio/detail/impl/win_event.ipp>
#include <boost/asio/detail/impl/win_mutex.ipp>
#include <boost/asio/detail/impl/win_thread.ipp>
#include <boost/asio/detail/impl/win_tss_ptr.ipp>
#include <boost/asio/detail/impl/winsock_init.ipp>
#include <boost/asio/ip/impl/address.ipp>
#include <boost/asio/ip/impl/address_v4.ipp>
#include <boost/asio/ip/impl/address_v6.ipp>
#include <boost/asio/ip/impl/host_name.ipp>
#include <boost/asio/ip/detail/impl/endpoint.ipp>
#include <boost/asio/local/detail/impl/endpoint.ipp>
#if BOOST_VERSION >= 104900
#include <boost/asio/detail/impl/win_object_handle_service.ipp>
#endif

#else // _MSC_VER

#if BOOST_VERSION >= 104500
#include <boost/asio/impl/src.hpp>
#elif BOOST_VERSION >= 104400
#include <boost/asio/impl/src.cpp>
#endif

#endif
<commit_msg>asio include fix<commit_after>// builds all boost.asio source as a separate compilation unit
#include <boost/version.hpp>

#ifndef BOOST_ASIO_SOURCE
#define BOOST_ASIO_SOURCE
#endif

#ifdef _MSC_VER > 1310

// on windows; including timer_queue.hpp results in an
// actual link-time dependency on boost.date_time, even
// though it's never referenced. So, avoid that on windows.
// on Mac OS X and Linux, not including it results in
// missing symbols. For some reason, this current setup
// works, at least across windows, Linux and Mac OS X.
// In the future this hack can be fixed by disabling
// use of boost.date_time in boost.asio

#include <boost/asio/detail/config.hpp>

#if defined(BOOST_ASIO_HEADER_ONLY)
# error Do not compile Asio library source with BOOST_ASIO_HEADER_ONLY defined
#endif

#include <boost/asio/impl/error.ipp>
#include <boost/asio/impl/io_service.ipp>
#include <boost/asio/impl/serial_port_base.ipp>
#include <boost/asio/detail/impl/descriptor_ops.ipp>
#include <boost/asio/detail/impl/dev_poll_reactor.ipp>
#include <boost/asio/detail/impl/epoll_reactor.ipp>
#include <boost/asio/detail/impl/eventfd_select_interrupter.ipp>
#if BOOST_VERSION >= 104700
#include <boost/asio/detail/impl/handler_tracking.ipp>
#include <boost/asio/detail/impl/signal_set_service.ipp>
#include <boost/asio/detail/impl/win_static_mutex.ipp>
#endif
#include <boost/asio/detail/impl/kqueue_reactor.ipp>
#include <boost/asio/detail/impl/pipe_select_interrupter.ipp>
#include <boost/asio/detail/impl/posix_event.ipp>
#include <boost/asio/detail/impl/posix_mutex.ipp>
#include <boost/asio/detail/impl/posix_thread.ipp>
#include <boost/asio/detail/impl/posix_tss_ptr.ipp>
#include <boost/asio/detail/impl/reactive_descriptor_service.ipp>
#include <boost/asio/detail/impl/reactive_serial_port_service.ipp>
#include <boost/asio/detail/impl/reactive_socket_service_base.ipp>
#include <boost/asio/detail/impl/resolver_service_base.ipp>
#include <boost/asio/detail/impl/select_reactor.ipp>
#include <boost/asio/detail/impl/service_registry.ipp>
#include <boost/asio/detail/impl/socket_ops.ipp>
#include <boost/asio/detail/impl/socket_select_interrupter.ipp>
#include <boost/asio/detail/impl/strand_service.ipp>
#include <boost/asio/detail/impl/task_io_service.ipp>
#include <boost/asio/detail/impl/throw_error.ipp>
//#include <boost/asio/detail/impl/timer_queue.ipp>
#include <boost/asio/detail/impl/timer_queue_set.ipp>
#include <boost/asio/detail/impl/win_iocp_handle_service.ipp>
#include <boost/asio/detail/impl/win_iocp_io_service.ipp>
#include <boost/asio/detail/impl/win_iocp_serial_port_service.ipp>
#include <boost/asio/detail/impl/win_iocp_socket_service_base.ipp>
#include <boost/asio/detail/impl/win_event.ipp>
#include <boost/asio/detail/impl/win_mutex.ipp>
#include <boost/asio/detail/impl/win_thread.ipp>
#include <boost/asio/detail/impl/win_tss_ptr.ipp>
#include <boost/asio/detail/impl/winsock_init.ipp>
#include <boost/asio/ip/impl/address.ipp>
#include <boost/asio/ip/impl/address_v4.ipp>
#include <boost/asio/ip/impl/address_v6.ipp>
#include <boost/asio/ip/impl/host_name.ipp>
#include <boost/asio/ip/detail/impl/endpoint.ipp>
#include <boost/asio/local/detail/impl/endpoint.ipp>
#if BOOST_VERSION >= 104900
#include <boost/asio/detail/impl/win_object_handle_service.ipp>
#endif

#else // _MSC_VER

#if BOOST_VERSION >= 104500
#include <boost/asio/impl/src.hpp>
#elif BOOST_VERSION >= 104400
#include <boost/asio/impl/src.cpp>
#endif

#endif
<|endoftext|>


<commit_before>AliAnalysisTaskPythiaNuclei* AddTaskPythiaNuclei(){

  AliAnalysisTaskPythiaNuclei *task = new AliAnalysisTaskPythiaNuclei("");

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();

  if (!mgr) {
    cout<<"AliAnalysisTaskPythiaNuclei","No analysis manager to connect to."<<endl;
    return NULL;
  }

  mgr->AddTask(task);

  // Create containers for input/output
  TString outputFileName = AliAnalysisManager::GetCommonFileName();

  AliAnalysisDataContainer *cinput = mgr->GetCommonInputContainer();
  AliAnalysisDataContainer *coutput = mgr->CreateContainer("fOutputList", TList::Class(),
    AliAnalysisManager::kOutputContainer,
    outputFileName);

  //connect containers
  mgr->ConnectInput(task, 0, cinput);
  mgr->ConnectOutput(task, 1, coutput);

  return task;
}
<commit_msg>Add subwagon compatibility to the AddTask macro<commit_after>AliAnalysisTaskPythiaNuclei* AddTaskPythiaNuclei(TString suffix = ""){

  AliAnalysisTaskPythiaNuclei *task = new AliAnalysisTaskPythiaNuclei(Form("nuclei%s",suffix.Data()));

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();

  if (!mgr) {
    cout<<"AliAnalysisTaskPythiaNuclei","No analysis manager to connect to."<<endl;
    return NULL;
  }

  mgr->AddTask(task);

  // Create containers for input/output
  TString outputFileName = AliAnalysisManager::GetCommonFileName();

  AliAnalysisDataContainer *cinput = mgr->GetCommonInputContainer();
  AliAnalysisDataContainer *coutput = mgr->CreateContainer(Form("fOutputList%s",suffix.Data()), TList::Class(),
    AliAnalysisManager::kOutputContainer,
    outputFileName);

  //connect containers
  mgr->ConnectInput(task, 0, cinput);
  mgr->ConnectOutput(task, 1, coutput);

  return task;
}
<|endoftext|>


<commit_before>/* base.cpp                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 29 Nov 2013
   FreeBSD-style copyright and disclaimer apply

   Endpoint base implementation.
*/

#include "base.h"
#include "utils.h"

#include <cassert>
#include <sys/epoll.h>

namespace slick {

/******************************************************************************/
/* ENDPOINT BASE                                                              */
/******************************************************************************/

EndpointBase::
EndpointBase() : pollThread(0)
{
    poller.add(messagesFd.fd());
}

EndpointBase::
~EndpointBase()
{
    // The extra step is required to not invalidate our iterator
    std::vector<int> toDisconnect;
    for (const auto& connection : connections)
        toDisconnect.push_back(connection.first);

    for (int fd : toDisconnect)
        disconnect(fd);
}

void
EndpointBase::
poll()
{
    pollThread = threadId();

    while(poller.poll()) {

        struct epoll_event ev = poller.next();

        if (connections.count(ev.data.fd)) {

            if (ev.events & EPOLLERR)
                connections[ev.data.fd].socket.throwError();

            if (ev.events & EPOLLIN) recvPayload(ev.data.fd);

            if (ev.events & EPOLLRDHUP || ev.events & EPOLLHUP) {
                disconnect(ev.data.fd);
                continue;
            }

            if (ev.events & EPOLLOUT) flushQueue(ev.data.fd);
        }

        else if (ev.data.fd == messagesFd.fd()) {
            SLICK_CHECK_ERRNO(!(ev.events & EPOLLERR),
                    "EndpointBase.meesageFd.EPOLLERR");
            flushMessages();
        }

        else {
            onPollEvent(ev);
        }
    }
}

void
EndpointBase::
connect(Socket&& socket)
{
    poller.add(socket.fd(), EPOLLET | EPOLLIN | EPOLLOUT);

    int fd = socket.fd();

    ConnectionState connection;
    connection.socket = std::move(socket);
    connections[connection.socket.fd()] = std::move(connection);

    if (onNewConnection) onNewConnection(fd);
}

void
EndpointBase::
disconnect(int fd)
{
    poller.del(fd);
    connections.erase(fd);

    if (onLostConnection) onLostConnection(fd);
}

uint8_t*
EndpointBase::
processRecvBuffer(int fd, uint8_t* first, uint8_t* last)
{
    uint8_t* it = first;

    while (it < last) {
        size_t leftover = last - it;
        Payload data = proto::fromBuffer(it, leftover);

        if (!data.packetSize()) {
            std::copy(it, last, first);
            return first + leftover;
        }

        it += data.packetSize();
        onPayload(fd, std::move(data));
    }

    assert(it == last);
    return last;
}

void
EndpointBase::
recvPayload(int fd)
{
    auto conn = connections.find(fd);
    assert(conn != connections.end());

    enum { bufferLength = 1U << 16 };
    uint8_t buffer[bufferLength];
    uint8_t* bufferIt = buffer;

    while (true) {
        ssize_t read = recv(fd, bufferIt, (buffer + bufferLength) - bufferIt, 0);

        if (read < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) break;
            if (errno == EINTR) continue;
            SLICK_CHECK_ERRNO(read != -1, "EndpointBase.recv");
        }

        if (!read) { // indicates that shutdown was called on the connection side.
            disconnect(fd);
            break;
        }

        conn->second.bytesRecv += read;
        bufferIt = processRecvBuffer(fd, buffer, bufferIt + read);
    }
}

namespace {

// This is not part of the class EndpointBase because we don't want to make
// it part of the header.

template<typename Payload>
bool sendTo(EndpointBase::ConnectionState& conn, Payload&& data)
{
    (void) conn;
    (void) data;

    if (!conn.writable) {
        conn.sendQueue.emplace_back(std::forward<Payload>(data));
        return true;
    }
    ssize_t sent = send(
            conn.socket.fd(), data.packet(), data.packetSize(), MSG_NOSIGNAL);
    if (sent >= 0) {
        assert(size_t(sent) == data.packetSize());
        return true;
    }

    if (errno == EAGAIN || errno == EWOULDBLOCK) {
        conn.sendQueue.emplace_back(std::forward<Payload>(data));
        return true;
    }

    else if (errno == ECONNRESET || errno == EPIPE) return false;
    SLICK_CHECK_ERRNO(sent >= 0, "EndpointBase.sendTo.send");

    conn.bytesSent += sent;
    return true;
}

} // namespace anonymous

void
EndpointBase::
send(int fd, Payload&& msg)
{
    if (threadId() != pollThread) {
        messages.push(Message(fd, std::move(msg)));
        messagesFd.signal();
        return;
    }

    auto it = connections.find(fd);
    assert(it != connections.end());

    if (!sendTo(it->second, std::move(msg)))
        disconnect(it->first);
}

void
EndpointBase::
broadcast(Payload&& msg)
{
    if (threadId() != pollThread) {
        messages.push(Message(std::move(msg)));
        messagesFd.signal();
        return;
    }

    std::vector<int> toDisconnect;

    for (auto& connection : connections) {
        if (!sendTo(connection.second, msg))
            toDisconnect.push_back(connection.first);
    }

    for (int fd : toDisconnect) disconnect(fd);
}

void
EndpointBase::
flushQueue(int fd)
{
    auto it = connections.find(fd);
    assert(it != connections.end());

    ConnectionState& connection = it->second;
    connection.writable = true;

    std::vector<Payload> queue = std::move(connection.sendQueue);
    for (auto& msg : queue) {
        if (sendTo(connection, std::move(msg))) continue;

        disconnect(fd);
        break;
    }
}

void
EndpointBase::
flushMessages()
{
    while (messagesFd.poll()) {
        while (!messages.empty()) {
            Message msg = messages.pop();

            if (msg.isBroadcast())
                broadcast(std::move(msg.data));
            else send(msg.conn, std::move(msg.data));
        }
    }
}

} // slick
<commit_msg>processRecvBuffer returns the right pointer after having consumed the entire buffer.<commit_after>/* base.cpp                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 29 Nov 2013
   FreeBSD-style copyright and disclaimer apply

   Endpoint base implementation.
*/

#include "base.h"
#include "utils.h"

#include <cassert>
#include <sys/epoll.h>

namespace slick {

/******************************************************************************/
/* ENDPOINT BASE                                                              */
/******************************************************************************/

EndpointBase::
EndpointBase() : pollThread(0)
{
    poller.add(messagesFd.fd());
}

EndpointBase::
~EndpointBase()
{
    // The extra step is required to not invalidate our iterator
    std::vector<int> toDisconnect;
    for (const auto& connection : connections)
        toDisconnect.push_back(connection.first);

    for (int fd : toDisconnect)
        disconnect(fd);
}

void
EndpointBase::
poll()
{
    pollThread = threadId();

    while(poller.poll()) {

        struct epoll_event ev = poller.next();

        if (connections.count(ev.data.fd)) {

            if (ev.events & EPOLLERR)
                connections[ev.data.fd].socket.throwError();

            if (ev.events & EPOLLIN) recvPayload(ev.data.fd);

            if (ev.events & EPOLLRDHUP || ev.events & EPOLLHUP) {
                disconnect(ev.data.fd);
                continue;
            }

            if (ev.events & EPOLLOUT) flushQueue(ev.data.fd);
        }

        else if (ev.data.fd == messagesFd.fd()) {
            SLICK_CHECK_ERRNO(!(ev.events & EPOLLERR),
                    "EndpointBase.meesageFd.EPOLLERR");
            flushMessages();
        }

        else {
            onPollEvent(ev);
        }
    }
}

void
EndpointBase::
connect(Socket&& socket)
{
    poller.add(socket.fd(), EPOLLET | EPOLLIN | EPOLLOUT);

    int fd = socket.fd();

    ConnectionState connection;
    connection.socket = std::move(socket);
    connections[connection.socket.fd()] = std::move(connection);

    if (onNewConnection) onNewConnection(fd);
}

void
EndpointBase::
disconnect(int fd)
{
    poller.del(fd);
    connections.erase(fd);

    if (onLostConnection) onLostConnection(fd);
}

uint8_t*
EndpointBase::
processRecvBuffer(int fd, uint8_t* first, uint8_t* last)
{
    uint8_t* it = first;

    while (it < last) {
        size_t leftover = last - it;
        Payload data = proto::fromBuffer(it, leftover);

        if (!data.packetSize()) {
            std::copy(it, last, first);
            return first + leftover;
        }

        it += data.packetSize();
        onPayload(fd, std::move(data));
    }

    assert(it == last);
    return first;
}

void
EndpointBase::
recvPayload(int fd)
{
    auto conn = connections.find(fd);
    assert(conn != connections.end());

    enum { bufferLength = 1U << 16 };
    uint8_t buffer[bufferLength];
    uint8_t* bufferIt = buffer;

    while (true) {
        ssize_t read = recv(fd, bufferIt, (buffer + bufferLength) - bufferIt, 0);

        if (read < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) break;
            if (errno == EINTR) continue;
            SLICK_CHECK_ERRNO(read != -1, "EndpointBase.recv");
        }

        if (!read) { // indicates that shutdown was called on the connection side.
            disconnect(fd);
            break;
        }

        conn->second.bytesRecv += read;
        bufferIt = processRecvBuffer(fd, buffer, bufferIt + read);
    }
}

namespace {

// This is not part of the class EndpointBase because we don't want to make
// it part of the header.

template<typename Payload>
bool sendTo(EndpointBase::ConnectionState& conn, Payload&& data)
{
    (void) conn;
    (void) data;

    if (!conn.writable) {
        conn.sendQueue.emplace_back(std::forward<Payload>(data));
        return true;
    }
    ssize_t sent = send(
            conn.socket.fd(), data.packet(), data.packetSize(), MSG_NOSIGNAL);
    if (sent >= 0) {
        assert(size_t(sent) == data.packetSize());
        return true;
    }

    if (errno == EAGAIN || errno == EWOULDBLOCK) {
        conn.sendQueue.emplace_back(std::forward<Payload>(data));
        return true;
    }

    else if (errno == ECONNRESET || errno == EPIPE) return false;
    SLICK_CHECK_ERRNO(sent >= 0, "EndpointBase.sendTo.send");

    conn.bytesSent += sent;
    return true;
}

} // namespace anonymous

void
EndpointBase::
send(int fd, Payload&& msg)
{
    if (threadId() != pollThread) {
        messages.push(Message(fd, std::move(msg)));
        messagesFd.signal();
        return;
    }

    auto it = connections.find(fd);
    assert(it != connections.end());

    if (!sendTo(it->second, std::move(msg)))
        disconnect(it->first);
}

void
EndpointBase::
broadcast(Payload&& msg)
{
    if (threadId() != pollThread) {
        messages.push(Message(std::move(msg)));
        messagesFd.signal();
        return;
    }

    std::vector<int> toDisconnect;

    for (auto& connection : connections) {
        if (!sendTo(connection.second, msg))
            toDisconnect.push_back(connection.first);
    }

    for (int fd : toDisconnect) disconnect(fd);
}

void
EndpointBase::
flushQueue(int fd)
{
    auto it = connections.find(fd);
    assert(it != connections.end());

    ConnectionState& connection = it->second;
    connection.writable = true;

    std::vector<Payload> queue = std::move(connection.sendQueue);
    for (auto& msg : queue) {
        if (sendTo(connection, std::move(msg))) continue;

        disconnect(fd);
        break;
    }
}

void
EndpointBase::
flushMessages()
{
    while (messagesFd.poll()) {
        while (!messages.empty()) {
            Message msg = messages.pop();

            if (msg.isBroadcast())
                broadcast(std::move(msg.data));
            else send(msg.conn, std::move(msg.data));
        }
    }
}

} // slick
<|endoftext|>


<commit_before>#include <string.h>

#include "s_object.h"
#include "s_runtime.h"
#include "s_gc.h"

#include "u_new.h"
#include "u_assert.h"
#include "u_log.h"

namespace s {

// TODO(daleweiler): make this part of the virtual machine state
Object *Object::m_lastAllocated;
size_t Object::m_numAllocated;
size_t Object::m_nextGCRun = 10000;

///! Table
Object **Table::lookupReference(const char *key, Table::Entry **first) {
    if (!m_entry.m_name) {
        if (first)
            *first = &m_entry;
        return nullptr;
    }

    Entry *entry = &m_entry;
    Entry *prev;
    while (entry) {
        if (strcmp(key, entry->m_name) == 0)
            return &entry->m_value;
        prev = entry;
        entry = entry->m_next;
    }

    if (first) {
        Entry *next = (Entry *)neoCalloc(sizeof *next, 1);
        prev->m_next = next;
        *first = next;
    }

    return nullptr;
};

Object *Table::lookup(const char *key, bool *found) {
    Object **find = lookupReference(key, nullptr);
    if (!find) {
        if (found)
            *found = false;
        return nullptr;
    }
    if (found)
        *found = true;
    return *find;
}

Object *Object::lookup(const char *key, bool *found) {
    Object *object = this;
    while (object) {
        bool keyFound;
        Object *value = object->m_table.lookup(key, &keyFound);
        if (keyFound) {
            if (found)
                *found = true;
            return value;
        }
        object = object->m_parent;
    }
    if (found)
        *found = false;
    return nullptr;
}

///! Object
void Object::mark(Object *context, Object *object) {
    // break cycles
    if (!object || object->m_flags & kMarked)
        return;
    object->m_flags |= kMarked;

    // mark parent object
    mark(context, object->m_parent);

    // mark all entries in the table
    Table::Entry *entry = &object->m_table.m_entry;
    while (entry) {
        mark(context, entry->m_value);
        entry = entry->m_next;
    }

    // check for mark function and call it if exists
    bool markFunctionFound;
    Object *markFunction = object->lookup("mark", &markFunctionFound);
    if (markFunctionFound) {
        FunctionObject *markFunctionObject = (FunctionObject *)markFunction;
        markFunctionObject->m_function(context, object, markFunction, nullptr, 0);
    }
}

void Object::free(Object *object) {
    Table::Entry *entry = object->m_table.m_entry.m_next;
    while (entry) {
        Table::Entry *next = entry->m_next;
        neoFree(entry);
        entry = next;
    }
    neoFree(object);
}

Object *Object::instanceOf(Object *object, Object *prototype) {
    // search the prototype chain to see if 'object' is an instance of 'prototype'
    while (object) {
        if (object->m_parent == prototype)
            return object;
        object = object->m_parent;
    }
    return nullptr;
}

// changes a propery in place
void Object::setExisting(const char *key, Object *value) {
    Object *current = this;
    while (current) {
        Object **find = current->m_table.lookupReference(key, nullptr);
        if (find) {
            U_ASSERT(!(m_flags & kImmutable));
            *find = value;
            return;
        }
        current = current->m_parent;
    }
    U_UNREACHABLE();
}

// change a propery only if it exists somewhere in the prototype chain
void Object::setShadowing(const char *key, Object *value) {
    Object *current = this;
    while (current) {
        Object **find = current->m_table.lookupReference(key, nullptr);
        if (find) {
            // Create it in the object
            setNormal(key, value);
            return;
        }
        current = current->m_parent;
    }

    U_UNREACHABLE();
}

// set property
void Object::setNormal(const char *key, Object *value) {
    Table::Entry *free = nullptr;
    Object **find = m_table.lookupReference(key, &free);
    if (find) {
        U_ASSERT(!(m_flags & kImmutable));
    } else {
        U_ASSERT(!(m_flags & kClosed));
        free->m_name = key;
        find = &free->m_value;
    }
    *find = value;
}

void *Object::alloc(Object *context, size_t size) {
    if (m_numAllocated > m_nextGCRun) {
        GarbageCollector::run(context);
        // TODO(daleweiler): cleanup in vm state ?
        m_nextGCRun = m_numAllocated * 1.2f;
    }

    Object *result = (Object *)neoCalloc(size, 1);
    result->m_prev = m_lastAllocated;
    m_lastAllocated = result;
    m_numAllocated++;
    return result;
}

Object *Object::newObject(Object *context, Object *parent) {
    Object *object = (Object *)alloc(context, sizeof(Object));
    object->m_parent = parent;
    return object;
}

Object *Object::newInt(Object *context, int value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *intBase = root->lookup("int", nullptr);
    auto *object = (IntObject *)alloc(context, sizeof(IntObject));
    object->m_parent = intBase;
    object->m_value = value;
    return (Object *)object;
}

Object *Object::newFloat(Object *context, float value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *floatBase = root->lookup("float", nullptr);
    auto *object = (FloatObject *)alloc(context, sizeof(FloatObject));
    object->m_parent = floatBase;
    object->m_flags = kImmutable | kClosed;
    object->m_value = value;
    return (Object *)object;
}

Object *Object::newBoolean(Object *context, bool value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *boolBase = root->lookup("bool", nullptr);
    auto *object = (BooleanObject *)alloc(context, sizeof(BooleanObject));
    object->m_parent = boolBase;
    object->m_flags = kImmutable | kClosed;
    object->m_value = value;
    return (Object *)object;
}

Object *Object::newString(Object *context, const char *value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *stringBase = root->lookup("string", nullptr);
    size_t length = strlen(value);
    // string gets allocated as part of the object
    auto *object = (StringObject *)alloc(context, sizeof(StringObject) + length + 1);
    object->m_parent = stringBase;
    object->m_flags = kImmutable | kClosed;
    object->m_value = ((char *)object) + sizeof(StringObject);
    strncpy(object->m_value, value, length + 1);
    return (Object *)object;
}

Object *Object::newArray(Object *context, Object **contents, size_t length) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *arrayBase = root->lookup("array", nullptr);
    auto *object = (ArrayObject *)alloc(context, sizeof(ArrayObject));
    object->m_parent = arrayBase;
    object->m_contents = contents;
    object->m_length = length;
    ((Object *)object)->setNormal("length", newInt(context, length));
    return (Object *)object;
}

Object *Object::newFunction(Object *context, FunctionPointer function) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *functionBase = root->lookup("function", nullptr);
    auto *object = (FunctionObject*)alloc(context, sizeof(FunctionObject));
    object->m_parent = functionBase;
    object->m_function = function;
    return (Object *)object;
}

Object *Object::newClosure(Object *context, UserFunction *function) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *closureBase = root->lookup("closure", nullptr);
    auto *object = (ClosureObject*)alloc(context, sizeof(ClosureObject));
    object->m_parent = closureBase;
    if (function->m_isMethod)
        object->m_function = methodHandler;
    else
        object->m_function = functionHandler;
    object->m_context = context;
    object->m_userFunction = *function;
    return (Object *)object;
}

}
<commit_msg>Pin when setting length property of array since newInt may trigger GC<commit_after>#include <string.h>

#include "s_object.h"
#include "s_runtime.h"
#include "s_gc.h"

#include "u_new.h"
#include "u_assert.h"
#include "u_log.h"

namespace s {

// TODO(daleweiler): make this part of the virtual machine state
Object *Object::m_lastAllocated;
size_t Object::m_numAllocated;
size_t Object::m_nextGCRun = 10000;

///! Table
Object **Table::lookupReference(const char *key, Table::Entry **first) {
    if (!m_entry.m_name) {
        if (first)
            *first = &m_entry;
        return nullptr;
    }

    Entry *entry = &m_entry;
    Entry *prev;
    while (entry) {
        if (strcmp(key, entry->m_name) == 0)
            return &entry->m_value;
        prev = entry;
        entry = entry->m_next;
    }

    if (first) {
        Entry *next = (Entry *)neoCalloc(sizeof *next, 1);
        prev->m_next = next;
        *first = next;
    }

    return nullptr;
};

Object *Table::lookup(const char *key, bool *found) {
    Object **find = lookupReference(key, nullptr);
    if (!find) {
        if (found)
            *found = false;
        return nullptr;
    }
    if (found)
        *found = true;
    return *find;
}

Object *Object::lookup(const char *key, bool *found) {
    Object *object = this;
    while (object) {
        bool keyFound;
        Object *value = object->m_table.lookup(key, &keyFound);
        if (keyFound) {
            if (found)
                *found = true;
            return value;
        }
        object = object->m_parent;
    }
    if (found)
        *found = false;
    return nullptr;
}

///! Object
void Object::mark(Object *context, Object *object) {
    // break cycles
    if (!object || object->m_flags & kMarked)
        return;
    object->m_flags |= kMarked;

    // mark parent object
    mark(context, object->m_parent);

    // mark all entries in the table
    Table::Entry *entry = &object->m_table.m_entry;
    while (entry) {
        mark(context, entry->m_value);
        entry = entry->m_next;
    }

    // check for mark function and call it if exists
    bool markFunctionFound;
    Object *markFunction = object->lookup("mark", &markFunctionFound);
    if (markFunctionFound) {
        FunctionObject *markFunctionObject = (FunctionObject *)markFunction;
        markFunctionObject->m_function(context, object, markFunction, nullptr, 0);
    }
}

void Object::free(Object *object) {
    Table::Entry *entry = object->m_table.m_entry.m_next;
    while (entry) {
        Table::Entry *next = entry->m_next;
        neoFree(entry);
        entry = next;
    }
    neoFree(object);
}

Object *Object::instanceOf(Object *object, Object *prototype) {
    // search the prototype chain to see if 'object' is an instance of 'prototype'
    while (object) {
        if (object->m_parent == prototype)
            return object;
        object = object->m_parent;
    }
    return nullptr;
}

// changes a propery in place
void Object::setExisting(const char *key, Object *value) {
    Object *current = this;
    while (current) {
        Object **find = current->m_table.lookupReference(key, nullptr);
        if (find) {
            U_ASSERT(!(m_flags & kImmutable));
            *find = value;
            return;
        }
        current = current->m_parent;
    }
    U_UNREACHABLE();
}

// change a propery only if it exists somewhere in the prototype chain
void Object::setShadowing(const char *key, Object *value) {
    Object *current = this;
    while (current) {
        Object **find = current->m_table.lookupReference(key, nullptr);
        if (find) {
            // Create it in the object
            setNormal(key, value);
            return;
        }
        current = current->m_parent;
    }

    U_UNREACHABLE();
}

// set property
void Object::setNormal(const char *key, Object *value) {
    Table::Entry *free = nullptr;
    Object **find = m_table.lookupReference(key, &free);
    if (find) {
        U_ASSERT(!(m_flags & kImmutable));
    } else {
        U_ASSERT(!(m_flags & kClosed));
        free->m_name = key;
        find = &free->m_value;
    }
    *find = value;
}

void *Object::alloc(Object *context, size_t size) {
    if (m_numAllocated > m_nextGCRun) {
        GarbageCollector::run(context);
        // TODO(daleweiler): cleanup in vm state ?
        m_nextGCRun = m_numAllocated * 1.2f;
    }

    Object *result = (Object *)neoCalloc(size, 1);
    result->m_prev = m_lastAllocated;
    m_lastAllocated = result;
    m_numAllocated++;
    return result;
}

Object *Object::newObject(Object *context, Object *parent) {
    Object *object = (Object *)alloc(context, sizeof(Object));
    object->m_parent = parent;
    return object;
}

Object *Object::newInt(Object *context, int value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *intBase = root->lookup("int", nullptr);
    auto *object = (IntObject *)alloc(context, sizeof(IntObject));
    object->m_parent = intBase;
    object->m_value = value;
    return (Object *)object;
}

Object *Object::newFloat(Object *context, float value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *floatBase = root->lookup("float", nullptr);
    auto *object = (FloatObject *)alloc(context, sizeof(FloatObject));
    object->m_parent = floatBase;
    object->m_flags = kImmutable | kClosed;
    object->m_value = value;
    return (Object *)object;
}

Object *Object::newBoolean(Object *context, bool value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *boolBase = root->lookup("bool", nullptr);
    auto *object = (BooleanObject *)alloc(context, sizeof(BooleanObject));
    object->m_parent = boolBase;
    object->m_flags = kImmutable | kClosed;
    object->m_value = value;
    return (Object *)object;
}

Object *Object::newString(Object *context, const char *value) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *stringBase = root->lookup("string", nullptr);
    size_t length = strlen(value);
    // string gets allocated as part of the object
    auto *object = (StringObject *)alloc(context, sizeof(StringObject) + length + 1);
    object->m_parent = stringBase;
    object->m_flags = kImmutable | kClosed;
    object->m_value = ((char *)object) + sizeof(StringObject);
    strncpy(object->m_value, value, length + 1);
    return (Object *)object;
}

Object *Object::newArray(Object *context, Object **contents, size_t length) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *arrayBase = root->lookup("array", nullptr);
    auto *object = (ArrayObject *)alloc(context, sizeof(ArrayObject));
    object->m_parent = arrayBase;
    object->m_contents = contents;
    object->m_length = length;
    // pin this since newInt may trigger the garbage collector
    void *pinned = GarbageCollector::addRoots(u::unsafe_cast<Object **>(&object), 1);
    ((Object *)object)->setNormal("length", newInt(context, length));
    GarbageCollector::delRoots(pinned);
    return (Object *)object;
}

Object *Object::newFunction(Object *context, FunctionPointer function) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *functionBase = root->lookup("function", nullptr);
    auto *object = (FunctionObject*)alloc(context, sizeof(FunctionObject));
    object->m_parent = functionBase;
    object->m_function = function;
    return (Object *)object;
}

Object *Object::newClosure(Object *context, UserFunction *function) {
    Object *root = context;
    while (root->m_parent)
        root = root->m_parent;
    Object *closureBase = root->lookup("closure", nullptr);
    auto *object = (ClosureObject*)alloc(context, sizeof(ClosureObject));
    object->m_parent = closureBase;
    if (function->m_isMethod)
        object->m_function = methodHandler;
    else
        object->m_function = functionHandler;
    object->m_context = context;
    object->m_userFunction = *function;
    return (Object *)object;
}

}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_CORE_SET_ZERO_ALL_ADJOINTS_NESTED_HPP
#define STAN_MATH_REV_CORE_SET_ZERO_ALL_ADJOINTS_NESTED_HPP

#include <stan/math/rev/core/chainable.hpp>
#include <stan/math/rev/core/chainable_alloc.hpp>
#include <stan/math/rev/core/chainablestack.hpp>

namespace stan {
  namespace math {

    /**
     * Reset all adjoint values in the top nested portion of the stack
     * to zero.
     */
    static void set_zero_all_adjoints_nested() {
      if (empty_nested())
        throw std::logic_error("empty_nested() must be false before calling"
                               " set_zero_all_adjoints_nested()");
      size_t start1 = ChainableStack::nested_var_stack_sizes_.back();
      for (size_t i = start1 - 1; i < ChainableStack::var_stack_.size(); ++i)
        ChainableStack::var_stack_[i]->set_zero_adjoint();

      size_t start2 = ChainableStack::nested_var_nochain_stack_sizes_.back();
      for (size_t i = start2 - 1;
           i < ChainableStack::var_nochain_stack_.size(); ++i)
        ChainableStack::var_nochain_stack_[i]->set_zero_adjoint();
    }

  }
}
#endif
<commit_msg>Update the new adjoint reset function to not use the deprecated chainable base class<commit_after>#ifndef STAN_MATH_REV_CORE_SET_ZERO_ALL_ADJOINTS_NESTED_HPP
#define STAN_MATH_REV_CORE_SET_ZERO_ALL_ADJOINTS_NESTED_HPP

#include <stan/math/rev/core/vari.hpp>
#include <stan/math/rev/core/chainable_alloc.hpp>
#include <stan/math/rev/core/chainablestack.hpp>

namespace stan {
  namespace math {

    /**
     * Reset all adjoint values in the top nested portion of the stack
     * to zero.
     */
    static void set_zero_all_adjoints_nested() {
      if (empty_nested())
        throw std::logic_error("empty_nested() must be false before calling"
                               " set_zero_all_adjoints_nested()");
      size_t start1 = ChainableStack::nested_var_stack_sizes_.back();
      for (size_t i = start1 - 1; i < ChainableStack::var_stack_.size(); ++i)
        ChainableStack::var_stack_[i]->set_zero_adjoint();

      size_t start2 = ChainableStack::nested_var_nochain_stack_sizes_.back();
      for (size_t i = start2 - 1;
           i < ChainableStack::var_nochain_stack_.size(); ++i)
        ChainableStack::var_nochain_stack_[i]->set_zero_adjoint();
    }

  }
}
#endif
<|endoftext|>


<commit_before>// Petter Strandmark 2013.

#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include <spii/string_utils.h>

using namespace spii;
using namespace std;

TEST_CASE("to_string")
{
	CHECK(to_string("Test",12,"test") == "Test12test");
}

TEST_CASE("to_string_pair")
{
	pair<int, string> p{123, "Test"};
	CHECK(to_string(p) == "(123, Test)");
}

TEST_CASE("to_string_pair_pair")
{
	auto p  = make_pair(123, "Test");
	auto pp = make_pair(12.1, p);
	CHECK(to_string(pp) == "(12.1, (123, Test))");
}

TEST_CASE("to_string_vector")
{
	vector<int> v{1, 2, 3};
	CHECK(to_string(v) == "[1, 2, 3]");
	v.clear();
	CHECK(to_string(v) == "[]");
}

TEST_CASE("to_string_vector_pair")
{
	vector<pair<int, string>> v{{1, "P"}, {2, "S"}};
	CHECK(to_string(v) == "[(1, P), (2, S)]");
}

TEST_CASE("to_string_set")
{
	set<int> v{1, 2, 3};
	CHECK(to_string(v) == "{1, 2, 3}");
	v.clear();
	CHECK(to_string(v) == "{}");
}

TEST_CASE("format_string_1")
{
	CHECK(format_string("Test %0!", 12) == "Test 12!");
	CHECK(format_string("Test %0", 12) == "Test 12");
}

TEST_CASE("format_string_%")
{
	CHECK(format_string("Test %0%%", 12) == "Test 12%");
	CHECK(format_string("Test %0%%!", 12) == "Test 12%!");
	CHECK(format_string("Test %0 %%", 12) == "Test 12 %");
	CHECK(format_string("Test %0 %%!", 12) == "Test 12 %!");
}

TEST_CASE("format_string_2")
{
	CHECK(format_string("Test %0 and %1!", 'A', 'O') == "Test A and O!");
	CHECK(format_string("Test %1 and %0!", 'A', 'O') == "Test O and A!");
}

TEST_CASE("from_string")
{
	CHECK(from_string<int>("42") == 42);
	CHECK(from_string("asd", 42) == 42);
	CHECK_THROWS(from_string<int>("abc"));
}
<commit_msg>Test std:: modifiers for to_string.<commit_after>// Petter Strandmark 2013.

#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include <spii/string_utils.h>

using namespace spii;
using namespace std;

TEST_CASE("to_string")
{
	CHECK(to_string("Test",12,"test") == "Test12test");
}

TEST_CASE("to_string_pair")
{
	pair<int, string> p{123, "Test"};
	CHECK(to_string(p) == "(123, Test)");
}

TEST_CASE("to_string_pair_pair")
{
	auto p  = make_pair(123, "Test");
	auto pp = make_pair(12.1, p);
	CHECK(to_string(pp) == "(12.1, (123, Test))");
}

TEST_CASE("to_string_vector")
{
	vector<int> v{1, 2, 3};
	CHECK(to_string(v) == "[1, 2, 3]");
	v.clear();
	CHECK(to_string(v) == "[]");
}

TEST_CASE("to_string_vector_pair")
{
	vector<pair<int, string>> v{{1, "P"}, {2, "S"}};
	CHECK(to_string(v) == "[(1, P), (2, S)]");
}

TEST_CASE("to_string_set")
{
	set<int> v{1, 2, 3};
	CHECK(to_string(v) == "{1, 2, 3}");
	v.clear();
	CHECK(to_string(v) == "{}");
}

TEST_CASE("to_string_setprecision")
{
	double d = 1.123456;
	CHECK(to_string(setprecision(2), d) == "1.1");
}

TEST_CASE("to_string_setfill_setw")
{
	CHECK(to_string(setfill('P'), setw(3), 1) == "PP1");
}

TEST_CASE("format_string_1")
{
	CHECK(format_string("Test %0!", 12) == "Test 12!");
	CHECK(format_string("Test %0", 12) == "Test 12");
}

TEST_CASE("format_string_%")
{
	CHECK(format_string("Test %0%%", 12) == "Test 12%");
	CHECK(format_string("Test %0%%!", 12) == "Test 12%!");
	CHECK(format_string("Test %0 %%", 12) == "Test 12 %");
	CHECK(format_string("Test %0 %%!", 12) == "Test 12 %!");
}

TEST_CASE("format_string_2")
{
	CHECK(format_string("Test %0 and %1!", 'A', 'O') == "Test A and O!");
	CHECK(format_string("Test %1 and %0!", 'A', 'O') == "Test O and A!");
}

TEST_CASE("from_string")
{
	CHECK(from_string<int>("42") == 42);
	CHECK(from_string("asd", 42) == 42);
	CHECK_THROWS(from_string<int>("abc"));
}
<|endoftext|>


<commit_before>#include <memory>
#include <gtest/gtest.h>
#include <parser.h>

using namespace lexers;
using namespace parser;

TEST(LibrariesParsingTest, BasicConsTest) {
Scope s;
lexers::Lexer lex("(load \"Base.scm\")");
parseExpr(lex)->eval(s);
ASSERT_TRUE(s
.count("cons"));
ASSERT_TRUE(s
.count("car"));
ASSERT_TRUE(s
.count("cdr"));

lex.appendExp("(define p (cons 1 2))").appendExp("(cdr p)");
auto res = parseAllExpr(lex)->eval(s);
ASSERT_TRUE(std::dynamic_pointer_cast<NumberAST>(res));
auto numPtr = std::dynamic_pointer_cast<NumberAST>(res);
ASSERT_EQ(2, numPtr->

getValue()

);

lex.appendExp("(car p)");
res = parseAllExpr(lex)->eval(s);
ASSERT_TRUE(std::dynamic_pointer_cast<NumberAST>(res));
numPtr = std::dynamic_pointer_cast<NumberAST>(res);
ASSERT_EQ(1, numPtr->

getValue()

);
}

TEST(LibrariesParsingTest, AdvanceConsTest
) {
Scope s;
lexers::Lexer lex;
lex.appendExp("(load \"Base.scm\")")
.appendExp("(define p (cons 1 2))")
.appendExp("(define pp (cons 3 p))")
.appendExp("(car (cdr pp))");

auto res = parseAllExpr(lex)->eval(s);
ASSERT_TRUE(std::dynamic_pointer_cast<NumberAST>(res));
auto numPtr = std::dynamic_pointer_cast<NumberAST>(res);
ASSERT_EQ(1, numPtr->

getValue()

);
}
<commit_msg>格式化代码<commit_after>#include <memory>
#include <gtest/gtest.h>
#include <parser.h>

using namespace lexers;
using namespace parser;

TEST(LibrariesParsingTest, BasicConsTest
) {
    Scope s;
    lexers::Lexer lex("(load \"Base.scm\")");
    parseExpr(lex)->eval(s);
    ASSERT_TRUE(s.count("cons"));
    ASSERT_TRUE(s.count("car"));
    ASSERT_TRUE(s.count("cdr"));

    lex.appendExp("(define p (cons 1 2))").appendExp("(cdr p)");
    auto res = parseAllExpr(lex)->eval(s);
    ASSERT_TRUE(std::dynamic_pointer_cast<NumberAST>(res));
    auto numPtr = std::dynamic_pointer_cast<NumberAST>(res);
    ASSERT_EQ(2, numPtr->getValue());

    lex.appendExp("(car p)");
    res = parseAllExpr(lex)->eval(s);
    ASSERT_TRUE(std::dynamic_pointer_cast<NumberAST>(res));
    numPtr = std::dynamic_pointer_cast<NumberAST>(res);
    ASSERT_EQ(1, numPtr->getValue());
}

TEST(LibrariesParsingTest, AdvanceConsTest
) {
    Scope s;
    lexers::Lexer lex;
    lex.appendExp("(load \"Base.scm\")")
            .appendExp("(define p (cons 1 2))")
            .appendExp("(define pp (cons 3 p))")
            .appendExp("(car (cdr pp))");

    auto res = parseAllExpr(lex)->eval(s);
    ASSERT_TRUE(std::dynamic_pointer_cast<NumberAST>(res));
    auto numPtr = std::dynamic_pointer_cast<NumberAST>(res);
    ASSERT_EQ(1, numPtr->getValue());
}
<|endoftext|>


<commit_before>#ifndef DUNE_DETAILED_DISCRETIZATIONS_LA_CONTAINER_FACTORY_EIGEN_HH
#define DUNE_DETAILED_DISCRETIZATIONS_LA_CONTAINER_FACTORY_EIGEN_HH

#include <dune/stuff/la/container/pattern.hh>
#include <dune/stuff/la/container/eigen.hh>

#include <dune/detailed/discretizations/space/interface.hh>

namespace Dune {
namespace Detailed {
namespace Discretizations {

template< class ElementType >
class ContainerFactoryEigen
{
public:
  typedef Dune::Stuff::LA::EigenRowMajorSparseMatrix< ElementType >  RowMajorSparseMatrixType;
  typedef Dune::Stuff::LA::EigenDenseMatrix< ElementType >           DenseMatrixType;
  typedef Dune::Stuff::LA::EigenDenseVector< ElementType >           DenseVectorType;
  typedef Dune::Stuff::LA::SparsityPatternDefault                    PatternType;

  template< class T, class A >
  static RowMajorSparseMatrixType* createRowMajorSparseMatrix(const SpaceInterface< T >& testSpace,
                                                              const SpaceInterface< A >& ansatzSpace)
  {
    const std::shared_ptr< const PatternType > pattern(testSpace.computePattern(ansatzSpace));
    return createRowMajorSparseMatrix(testSpace, ansatzSpace, *pattern);
  } // static ... createRowMajorSparseMatrix(...)

  template< class T, class A >
  static RowMajorSparseMatrixType* createRowMajorSparseMatrix(const SpaceInterface< T >& testSpace,
                                                              const SpaceInterface< A >& ansatzSpace,
                                                              const PatternType& pattern)
  {
    return new RowMajorSparseMatrixType(testSpace.mapper().size(),
                                        ansatzSpace.mapper().size(),
                                        pattern);
  } // static ... createRowMajorSparseMatrix(...)

  template< class T, class A >
  static DenseMatrixType createDenseMatrix(const SpaceInterface< T >& testSpace,
                                           const SpaceInterface< A >& ansatzSpace)
  {
    return new DenseMatrixType(testSpace.mapper().size(),
                               ansatzSpace.mapper().size());
  } // static ... createDenseMatrix(...)

  template< class S >
  static DenseVectorType* createDenseVector(const SpaceInterface< S >& space)
  {
    return new DenseVectorType(space.mapper().size());
  } // static ... createDenseVector(const SpaceType& space)
}; // class ContainerFactoryEigen

} // namespace Discretizations
} // namespace Detailed
} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_LA_CONTAINER_FACTORY_EIGEN_HH
<commit_msg>[la.containerfactory.eigen] minor fix<commit_after>#ifndef DUNE_DETAILED_DISCRETIZATIONS_LA_CONTAINER_FACTORY_EIGEN_HH
#define DUNE_DETAILED_DISCRETIZATIONS_LA_CONTAINER_FACTORY_EIGEN_HH

#include <dune/stuff/la/container/pattern.hh>
#include <dune/stuff/la/container/eigen.hh>

#include <dune/detailed/discretizations/space/interface.hh>

namespace Dune {
namespace Detailed {
namespace Discretizations {

template< class ElementType >
class ContainerFactoryEigen
{
public:
  typedef Dune::Stuff::LA::EigenRowMajorSparseMatrix< ElementType >  RowMajorSparseMatrixType;
  typedef Dune::Stuff::LA::EigenDenseMatrix< ElementType >           DenseMatrixType;
  typedef Dune::Stuff::LA::EigenDenseVector< ElementType >           DenseVectorType;
  typedef Dune::Stuff::LA::SparsityPatternDefault                    PatternType;

  template< class T, class A >
  static RowMajorSparseMatrixType* createRowMajorSparseMatrix(const SpaceInterface< T >& testSpace,
                                                              const SpaceInterface< A >& ansatzSpace)
  {
    const std::shared_ptr< const PatternType > pattern(testSpace.computePattern(ansatzSpace));
    return createRowMajorSparseMatrix(testSpace, ansatzSpace, *pattern);
  } // static ... createRowMajorSparseMatrix(...)

  template< class T, class A >
  static RowMajorSparseMatrixType* createRowMajorSparseMatrix(const SpaceInterface< T >& testSpace,
                                                              const SpaceInterface< A >& ansatzSpace,
                                                              const PatternType& pattern)
  {
    return new RowMajorSparseMatrixType(testSpace.mapper().size(),
                                        ansatzSpace.mapper().size(),
                                        pattern);
  } // static ... createRowMajorSparseMatrix(...)

  template< class T, class A >
  static DenseMatrixType *createDenseMatrix(const SpaceInterface< T >& testSpace,
                                            const SpaceInterface< A >& ansatzSpace)
  {
    return new DenseMatrixType(testSpace.mapper().size(),
                               ansatzSpace.mapper().size());
  } // static ... createDenseMatrix(...)

  template< class S >
  static DenseVectorType* createDenseVector(const SpaceInterface< S >& space)
  {
    return new DenseVectorType(space.mapper().size());
  } // static ... createDenseVector(const SpaceType& space)
}; // class ContainerFactoryEigen

} // namespace Discretizations
} // namespace Detailed
} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_LA_CONTAINER_FACTORY_EIGEN_HH
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/platform_test.h"
#include "base/task.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::WaitableEvent;

typedef PlatformTest WorkerPoolTest;

namespace {

class PostTaskTestTask : public Task {
 public:
  PostTaskTestTask(WaitableEvent* event) : event_(event) {
  }

  void Run() {
    event_->Signal();
  }

 private:
  WaitableEvent* event_;
};

TEST_F(WorkerPoolTest, PostTask) {
  WaitableEvent test_event(false, false);
  WaitableEvent long_test_event(false, false);
  bool signaled;

  WorkerPool::PostTask(FROM_HERE, new PostTaskTestTask(&test_event), false);
  WorkerPool::PostTask(FROM_HERE, new PostTaskTestTask(&long_test_event), true);

  signaled = test_event.Wait();
  EXPECT_TRUE(signaled);
  signaled = long_test_event.Wait();
  EXPECT_TRUE(signaled);
}

} // namespace
<commit_msg>Reading the comments on a later change, it seems I should have only used a copyright of 2008 on this new file, so this fixes it.<commit_after>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/platform_test.h"
#include "base/task.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::WaitableEvent;

typedef PlatformTest WorkerPoolTest;

namespace {

class PostTaskTestTask : public Task {
 public:
  PostTaskTestTask(WaitableEvent* event) : event_(event) {
  }

  void Run() {
    event_->Signal();
  }

 private:
  WaitableEvent* event_;
};

TEST_F(WorkerPoolTest, PostTask) {
  WaitableEvent test_event(false, false);
  WaitableEvent long_test_event(false, false);
  bool signaled;

  WorkerPool::PostTask(FROM_HERE, new PostTaskTestTask(&test_event), false);
  WorkerPool::PostTask(FROM_HERE, new PostTaskTestTask(&long_test_event), true);

  signaled = test_event.Wait();
  EXPECT_TRUE(signaled);
  signaled = long_test_event.Wait();
  EXPECT_TRUE(signaled);
}

} // namespace
<|endoftext|>