<commit_before>//===------------------------- chrono.cpp ---------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "chrono"
#include "cerrno"        // errno
#include "system_error"  // __throw_system_error
#include <time.h>        // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME

#if (__APPLE__)
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
#else
#define _LIBCXX_USE_CLOCK_GETTIME
#endif // __APPLE__

#if defined(_LIBCPP_WIN32API)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRA_LEAN
#include <Windows.h>
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
#include <winapifamily.h>
#endif
#else
#if !defined(CLOCK_REALTIME)
#include <sys/time.h>        // for gettimeofday and timeval
#endif // !defined(CLOCK_REALTIME)
#endif // defined(_LIBCPP_WIN32API)

#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
#if __APPLE__
#include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
#elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC)
#error "Monotonic clock not implemented"
#endif
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

namespace chrono
{

// system_clock

const bool system_clock::is_steady;

system_clock::time_point
system_clock::now() _NOEXCEPT
{
#if defined(_LIBCPP_WIN32API)
  // FILETIME is in 100ns units
  using filetime_duration =
      _VSTD::chrono::duration<__int64,
                              _VSTD::ratio_multiply<_VSTD::ratio<100, 1>,
                                                    nanoseconds::period>>;

  // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.
  static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600};

  FILETIME ft;
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
  GetSystemTimePreciseAsFileTime(&ft);
#else
  GetSystemTimeAsFileTime(&ft);
#endif
#else
  GetSystemTimeAsFileTime(&ft);
#endif

  filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) |
                       static_cast<__int64>(ft.dwLowDateTime)};
  return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
#else
#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_REALTIME, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
    return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
#else
    timeval tv;
    gettimeofday(&tv, 0);
    return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
#endif // _LIBCXX_USE_CLOCK_GETTIME && CLOCK_REALTIME
#endif
}

time_t
system_clock::to_time_t(const time_point& t) _NOEXCEPT
{
    return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
}

system_clock::time_point
system_clock::from_time_t(time_t t) _NOEXCEPT
{
    return system_clock::time_point(seconds(t));
}

#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
// steady_clock
//
// Warning:  If this is not truly steady, then it is non-conforming.  It is
//  better for it to not exist and have the rest of libc++ use system_clock
//  instead.

const bool steady_clock::is_steady;

#if defined(__APPLE__)

// Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW
#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_UPTIME_RAW, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_UPTIME_RAW) failed");
    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}

#else
//   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
//   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
//   are run time constants supplied by the OS.  This clock has no relationship
//   to the Gregorian calendar.  It's main use is as a high resolution timer.

// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
//   for that case as an optimization.

static
steady_clock::rep
steady_simplified()
{
    return static_cast<steady_clock::rep>(mach_absolute_time());
}

static
double
compute_steady_factor()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    return static_cast<double>(MachInfo.numer) / MachInfo.denom;
}

static
steady_clock::rep
steady_full()
{
    static const double factor = compute_steady_factor();
    return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
}

typedef steady_clock::rep (*FP)();

static
FP
init_steady_clock()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    if (MachInfo.numer == MachInfo.denom)
        return &steady_simplified;
    return &steady_full;
}

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    static FP fp = init_steady_clock();
    return time_point(duration(fp()));
}
#endif // defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)

#elif defined(_LIBCPP_WIN32API)

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
  static LARGE_INTEGER freq;
  static BOOL initialized = FALSE;
  if (!initialized)
    initialized = QueryPerformanceFrequency(&freq); // always succceeds

  LARGE_INTEGER counter;
  QueryPerformanceCounter(&counter);
  return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart));
}

#elif defined(CLOCK_MONOTONIC)

// On Apple platforms only CLOCK_UPTIME_RAW or mach_absolute_time are able to
// time functions in the nanosecond range. Thus, they are the only acceptable
// implementations of steady_clock.
#ifdef __APPLE__
#error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms"
#endif

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}

#else
#error "Monotonic clock not implemented"
#endif

#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK

}

_LIBCPP_END_NAMESPACE_STD
<commit_msg>[Chrono][Darwin] Include header for gettimeofday<commit_after>//===------------------------- chrono.cpp ---------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "chrono"
#include "cerrno"        // errno
#include "system_error"  // __throw_system_error
#include <time.h>        // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME

#if (__APPLE__)
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000
#define _LIBCXX_USE_CLOCK_GETTIME
#endif
#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
#else
#define _LIBCXX_USE_CLOCK_GETTIME
#endif // __APPLE__

#if defined(_LIBCPP_WIN32API)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRA_LEAN
#include <Windows.h>
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
#include <winapifamily.h>
#endif
#else
#if !defined(CLOCK_REALTIME) || !defined(_LIBCXX_USE_CLOCK_GETTIME)
#include <sys/time.h>        // for gettimeofday and timeval
#endif // !defined(CLOCK_REALTIME)
#endif // defined(_LIBCPP_WIN32API)

#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
#if __APPLE__
#include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
#elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC)
#error "Monotonic clock not implemented"
#endif
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

namespace chrono
{

// system_clock

const bool system_clock::is_steady;

system_clock::time_point
system_clock::now() _NOEXCEPT
{
#if defined(_LIBCPP_WIN32API)
  // FILETIME is in 100ns units
  using filetime_duration =
      _VSTD::chrono::duration<__int64,
                              _VSTD::ratio_multiply<_VSTD::ratio<100, 1>,
                                                    nanoseconds::period>>;

  // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.
  static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600};

  FILETIME ft;
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
  GetSystemTimePreciseAsFileTime(&ft);
#else
  GetSystemTimeAsFileTime(&ft);
#endif
#else
  GetSystemTimeAsFileTime(&ft);
#endif

  filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) |
                       static_cast<__int64>(ft.dwLowDateTime)};
  return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
#else
#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_REALTIME, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
    return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
#else
    timeval tv;
    gettimeofday(&tv, 0);
    return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
#endif // _LIBCXX_USE_CLOCK_GETTIME && CLOCK_REALTIME
#endif
}

time_t
system_clock::to_time_t(const time_point& t) _NOEXCEPT
{
    return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
}

system_clock::time_point
system_clock::from_time_t(time_t t) _NOEXCEPT
{
    return system_clock::time_point(seconds(t));
}

#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
// steady_clock
//
// Warning:  If this is not truly steady, then it is non-conforming.  It is
//  better for it to not exist and have the rest of libc++ use system_clock
//  instead.

const bool steady_clock::is_steady;

#if defined(__APPLE__)

// Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW
#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_UPTIME_RAW, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_UPTIME_RAW) failed");
    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}

#else
//   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
//   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
//   are run time constants supplied by the OS.  This clock has no relationship
//   to the Gregorian calendar.  It's main use is as a high resolution timer.

// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
//   for that case as an optimization.

static
steady_clock::rep
steady_simplified()
{
    return static_cast<steady_clock::rep>(mach_absolute_time());
}

static
double
compute_steady_factor()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    return static_cast<double>(MachInfo.numer) / MachInfo.denom;
}

static
steady_clock::rep
steady_full()
{
    static const double factor = compute_steady_factor();
    return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
}

typedef steady_clock::rep (*FP)();

static
FP
init_steady_clock()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    if (MachInfo.numer == MachInfo.denom)
        return &steady_simplified;
    return &steady_full;
}

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    static FP fp = init_steady_clock();
    return time_point(duration(fp()));
}
#endif // defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)

#elif defined(_LIBCPP_WIN32API)

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
  static LARGE_INTEGER freq;
  static BOOL initialized = FALSE;
  if (!initialized)
    initialized = QueryPerformanceFrequency(&freq); // always succceeds

  LARGE_INTEGER counter;
  QueryPerformanceCounter(&counter);
  return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart));
}

#elif defined(CLOCK_MONOTONIC)

// On Apple platforms only CLOCK_UPTIME_RAW or mach_absolute_time are able to
// time functions in the nanosecond range. Thus, they are the only acceptable
// implementations of steady_clock.
#ifdef __APPLE__
#error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms"
#endif

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}

#else
#error "Monotonic clock not implemented"
#endif

#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK

}

_LIBCPP_END_NAMESPACE_STD
<|endoftext|>


<commit_before>/**
 * Copyright 2008 Matthew Graham
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "client.h"
#include "command.h"
#include "message.h"
#include "request.h"
#include "response.h"

#include "connection.h"

client_c::client_c()
: m_connection( NULL )
{}

client_c::client_c( connection_i &conn )
: m_connection( &conn )
{}

void client_c::send_request( command_i &cmd )
{
	// send_message( cmd.command_request() );
	// message_queue_i &queue( m_factory.message() );
	// queue.
	if ( ! m_connection )
		return;

	std::ostringstream out;
	const request_c &req( cmd.command_request() );
	m_connection->write_line( req.arg_string() );
}

void client_c::wait_for_response( command_i &cmd )
{
}

<commit_msg>implemented client.wait_for_response()<commit_after>/**
 * Copyright 2008 Matthew Graham
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "client.h"
#include "command.h"
#include "message.h"
#include "request.h"
#include "response.h"

#include "connection.h"

client_c::client_c()
: m_connection( NULL )
{}

client_c::client_c( connection_i &conn )
: m_connection( &conn )
{}

void client_c::send_request( command_i &cmd )
{
	// send_message( cmd.command_request() );
	// message_queue_i &queue( m_factory.message() );
	// queue.
	if ( ! m_connection )
		return;

	std::ostringstream out;
	const request_c &req( cmd.command_request() );
	m_connection->write_line( req.arg_string() );
}

void client_c::wait_for_response( command_i &cmd )
{
	std::string response_line;
	m_connection->read_line( response_line );
	cmd.command_response().parse_args( response_line );
}

<|endoftext|>


<commit_before>#include <glib.h>
#include <nan.h>

#include "closure.h"
#include "macros.h"
#include "loop.h"
#include "type.h"
#include "value.h"

using v8::Context;
using v8::Function;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Value;
using Nan::Persistent;

namespace GNodeJS {

// locking and signalling adapted from https://github.com/node-ffi-napi/node-ffi-napi
uv_async_t Closure::asyncHandle;

void Closure::Initialize() {
    auto& handle = Closure::asyncHandle;
    AsyncCallEnvironment* env = new AsyncCallEnvironment();
    handle.data = env;
    env->mainThread = uv_thread_self();
    uv_loop_t* loop = uv_default_loop();
    uv_async_init(loop, &handle, Closure::QueueHandler);
    uv_mutex_init(&env->mutex);
    uv_unref(reinterpret_cast<uv_handle_t *>(&handle));
    uv_async_send(&handle);
}

GClosure *Closure::New(Local<Function> function, GICallableInfo* info, guint signalId) {
    Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), GUINT_TO_POINTER(signalId));
    closure->persistent.Reset(function);
    if (info) {
        closure->info = g_base_info_ref(info);
    } else {
        closure->info = NULL;
    }
    GClosure *gclosure = &closure->base;
    g_closure_set_marshal (gclosure, Closure::Marshal);
    g_closure_add_invalidate_notifier (gclosure, NULL, Closure::Invalidated);
    return gclosure;
}

void Closure::Execute(GICallableInfo *info, guint signal_id,
                      const Nan::Persistent<v8::Function> &persFn,
                      GValue *g_return_value, uint n_param_values,
                      const GValue *param_values) {
    Nan::HandleScope scope;
    auto fn = Nan::New<Function>(persFn);

    GSignalQuery signal_query = { 0, };
    g_signal_query(signal_id, &signal_query);

    uint n_js_args = n_param_values - 1;
    #ifndef __linux__
        Local<Value> *js_args = new Local<Value>[n_js_args];
    #else
        Local<Value> js_args[n_js_args];
    #endif

    if (info) {
        /* CallableInfo is available: use GIArgumentToV8 */
        g_base_info_ref(info);
        GIArgument argument;
        GIArgInfo arg_info;
        GITypeInfo type_info;
        for (uint i = 0; i < n_js_args; i++) {
            memcpy(&argument, &param_values[i + 1].data[0], sizeof(GIArgument));
            g_callable_info_load_arg(info, i, &arg_info);
            g_arg_info_load_type(&arg_info, &type_info);

            bool mustCopy = true;

            if (signal_query.signal_id) {
                mustCopy = (signal_query.param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0;
            }

            js_args[i] = GIArgumentToV8(&type_info, &argument, -1, mustCopy);
        }
        g_base_info_unref(info);
    } else {
        /* CallableInfo is not available: use GValueToV8 */
        for (uint i = 0; i < n_js_args; i++) {
            bool mustCopy = true;

            if (signal_query.signal_id) {
                mustCopy = (signal_query.param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0;
            }
            js_args[i] = GValueToV8(&param_values[i + 1], mustCopy);
        }
    }

    Local<Object> self = fn;
    Local<Value> return_value;

    Nan::TryCatch try_catch;

    auto result = Nan::Call(fn, self, n_js_args, js_args);

    if (!try_catch.HasCaught() && result.ToLocal(&return_value)) {
        if (g_return_value) {
            if (G_VALUE_TYPE(g_return_value) == G_TYPE_INVALID)
            WARN("Marshal: return value has invalid g_type");
            else if (!V8ToGValue(g_return_value, return_value, true))
            WARN("Marshal: could not convert return value");
        }
        CallMicrotaskHandlers();
    } else {
        GNodeJS::QuitLoopStack();
        Nan::FatalException(try_catch);
    }

    #ifndef __linux__
        delete[] js_args;
    #endif
}

void Closure::Marshal(GClosure     *base,
                      GValue       *g_return_value,
                      uint          n_param_values,
                      const GValue *param_values,
                      gpointer      invocation_hint,
                      gpointer      marshal_data) {

    auto closure = (Closure *) base;
    auto signal_id = GPOINTER_TO_UINT(marshal_data);

    AsyncCallEnvironment* env = reinterpret_cast<AsyncCallEnvironment *>(Closure::asyncHandle.data);
    uv_thread_t thread = uv_thread_self();

    /* Case 1: same thread */
    if (uv_thread_equal(&thread, &env->mainThread)) {
        Closure::Execute(closure->info, signal_id, closure->persistent, g_return_value, n_param_values, param_values);
        return;
    }

    /* Case 2: different thread */
    CallbackWrapper cb(closure->info, signal_id, &closure->persistent, g_return_value, n_param_values, param_values);

    uv_mutex_lock(&env->mutex);
    env->queue.push(&cb);
    uv_mutex_unlock(&env->mutex);
    uv_async_send(&Closure::asyncHandle);

    cb.Wait();
}

void Closure::Invalidated (gpointer data, GClosure *base) {
    Closure *closure = (Closure *) base;
    closure->~Closure();
}

void Closure::QueueHandler(uv_async_t* handle) {
    AsyncCallEnvironment* data = reinterpret_cast<AsyncCallEnvironment *>(handle->data);
    uv_mutex_lock(&data->mutex);

    while (!data->queue.empty()) {
        CallbackWrapper* cb = data->queue.front();
        cb->Execute();
        data->queue.pop();
    }

    uv_mutex_unlock(&data->mutex);
}

CallbackWrapper::CallbackWrapper(GICallableInfo *info, guint signal_id,
                                 const Nan::Persistent<v8::Function> *persistent,
                                 GValue *returnValue, uint nValues,
                                 const GValue *values) : info(info), signal_id(signal_id), persistent(persistent), returnValue(returnValue), nValues(nValues) {
    uv_mutex_init(&mutex);
    uv_mutex_lock(&mutex);
    uv_cond_init(&cond);

    // copy values
    g_base_info_ref(info);
    this->values = new GValue[nValues];
    for (uint i = 0; i < nValues; ++i) {
        this->values[i] = G_VALUE_INIT;
        g_value_init(&this->values[i], G_VALUE_TYPE(&values[i]));
        g_value_copy(&values[i], &this->values[i]);
    }
}

CallbackWrapper::~CallbackWrapper() {
    g_base_info_unref(info);

    uv_mutex_unlock(&mutex);
    uv_cond_destroy(&cond);
    uv_mutex_destroy(&mutex);
}

void CallbackWrapper::Execute() {
    Closure::Execute(info, signal_id, *persistent, returnValue, nValues, values);
    Done();
}

void CallbackWrapper::Done() {
    uv_mutex_lock(&mutex);
    uv_cond_signal(&cond);
    uv_mutex_unlock(&mutex);
}
void CallbackWrapper::Wait() {
    uv_cond_wait(&cond, &mutex);
}

};
<commit_msg>Cleanup resources<commit_after>#include <glib.h>
#include <nan.h>

#include "closure.h"
#include "macros.h"
#include "loop.h"
#include "type.h"
#include "value.h"

using v8::Context;
using v8::Function;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Value;
using Nan::Persistent;

namespace GNodeJS {

// locking and signalling adapted from https://github.com/node-ffi-napi/node-ffi-napi
uv_async_t Closure::asyncHandle;

void Closure::Initialize() {
    auto& handle = Closure::asyncHandle;
    AsyncCallEnvironment* env = new AsyncCallEnvironment();
    handle.data = env;
    env->mainThread = uv_thread_self();
    uv_loop_t* loop = uv_default_loop();
    uv_async_init(loop, &handle, Closure::QueueHandler);
    uv_mutex_init(&env->mutex);
    uv_unref(reinterpret_cast<uv_handle_t *>(&handle));
    uv_async_send(&handle);
}

GClosure *Closure::New(Local<Function> function, GICallableInfo* info, guint signalId) {
    Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), GUINT_TO_POINTER(signalId));
    closure->persistent.Reset(function);
    if (info) {
        closure->info = g_base_info_ref(info);
    } else {
        closure->info = NULL;
    }
    GClosure *gclosure = &closure->base;
    g_closure_set_marshal (gclosure, Closure::Marshal);
    g_closure_add_invalidate_notifier (gclosure, NULL, Closure::Invalidated);
    return gclosure;
}

void Closure::Execute(GICallableInfo *info, guint signal_id,
                      const Nan::Persistent<v8::Function> &persFn,
                      GValue *g_return_value, uint n_param_values,
                      const GValue *param_values) {
    Nan::HandleScope scope;
    auto fn = Nan::New<Function>(persFn);

    GSignalQuery signal_query = { 0, };
    g_signal_query(signal_id, &signal_query);

    uint n_js_args = n_param_values - 1;
    #ifndef __linux__
        Local<Value> *js_args = new Local<Value>[n_js_args];
    #else
        Local<Value> js_args[n_js_args];
    #endif

    if (info) {
        /* CallableInfo is available: use GIArgumentToV8 */
        g_base_info_ref(info);
        GIArgument argument;
        GIArgInfo arg_info;
        GITypeInfo type_info;
        for (uint i = 0; i < n_js_args; i++) {
            memcpy(&argument, &param_values[i + 1].data[0], sizeof(GIArgument));
            g_callable_info_load_arg(info, i, &arg_info);
            g_arg_info_load_type(&arg_info, &type_info);

            bool mustCopy = true;

            if (signal_query.signal_id) {
                mustCopy = (signal_query.param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0;
            }

            js_args[i] = GIArgumentToV8(&type_info, &argument, -1, mustCopy);
        }
        g_base_info_unref(info);
    } else {
        /* CallableInfo is not available: use GValueToV8 */
        for (uint i = 0; i < n_js_args; i++) {
            bool mustCopy = true;

            if (signal_query.signal_id) {
                mustCopy = (signal_query.param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0;
            }
            js_args[i] = GValueToV8(&param_values[i + 1], mustCopy);
        }
    }

    Local<Object> self = fn;
    Local<Value> return_value;

    Nan::TryCatch try_catch;

    auto result = Nan::Call(fn, self, n_js_args, js_args);

    if (!try_catch.HasCaught() && result.ToLocal(&return_value)) {
        if (g_return_value) {
            if (G_VALUE_TYPE(g_return_value) == G_TYPE_INVALID)
            WARN("Marshal: return value has invalid g_type");
            else if (!V8ToGValue(g_return_value, return_value, true))
            WARN("Marshal: could not convert return value");
        }
        CallMicrotaskHandlers();
    } else {
        GNodeJS::QuitLoopStack();
        Nan::FatalException(try_catch);
    }

    #ifndef __linux__
        delete[] js_args;
    #endif
}

void Closure::Marshal(GClosure     *base,
                      GValue       *g_return_value,
                      uint          n_param_values,
                      const GValue *param_values,
                      gpointer      invocation_hint,
                      gpointer      marshal_data) {

    auto closure = (Closure *) base;
    auto signal_id = GPOINTER_TO_UINT(marshal_data);

    AsyncCallEnvironment* env = reinterpret_cast<AsyncCallEnvironment *>(Closure::asyncHandle.data);
    uv_thread_t thread = uv_thread_self();

    /* Case 1: same thread */
    if (uv_thread_equal(&thread, &env->mainThread)) {
        Closure::Execute(closure->info, signal_id, closure->persistent, g_return_value, n_param_values, param_values);
        return;
    }

    /* Case 2: different thread */
    CallbackWrapper cb(closure->info, signal_id, &closure->persistent, g_return_value, n_param_values, param_values);

    uv_mutex_lock(&env->mutex);
    env->queue.push(&cb);
    uv_mutex_unlock(&env->mutex);
    uv_async_send(&Closure::asyncHandle);

    cb.Wait();
}

void Closure::Invalidated (gpointer data, GClosure *base) {
    Closure *closure = (Closure *) base;
    closure->~Closure();
}

void Closure::QueueHandler(uv_async_t* handle) {
    AsyncCallEnvironment* data = reinterpret_cast<AsyncCallEnvironment *>(handle->data);
    uv_mutex_lock(&data->mutex);

    while (!data->queue.empty()) {
        CallbackWrapper* cb = data->queue.front();
        cb->Execute();
        data->queue.pop();
    }

    uv_mutex_unlock(&data->mutex);
}

CallbackWrapper::CallbackWrapper(GICallableInfo *info, guint signal_id,
                                 const Nan::Persistent<v8::Function> *persistent,
                                 GValue *returnValue, uint nValues,
                                 const GValue *values) : info(info), signal_id(signal_id), persistent(persistent), returnValue(returnValue), nValues(nValues) {
    uv_mutex_init(&mutex);
    uv_mutex_lock(&mutex);
    uv_cond_init(&cond);

    // copy values
    g_base_info_ref(info);
    this->values = new GValue[nValues];
    for (uint i = 0; i < nValues; ++i) {
        this->values[i] = G_VALUE_INIT;
        g_value_init(&this->values[i], G_VALUE_TYPE(&values[i]));
        g_value_copy(&values[i], &this->values[i]);
    }
}

CallbackWrapper::~CallbackWrapper() {
    g_base_info_unref(info);
    for (uint i = 0; i < nValues; ++i) {
        g_value_unset(&values[i]);
    }
    delete[] values;

    uv_mutex_unlock(&mutex);
    uv_cond_destroy(&cond);
    uv_mutex_destroy(&mutex);
}

void CallbackWrapper::Execute() {
    Closure::Execute(info, signal_id, *persistent, returnValue, nValues, values);
    Done();
}

void CallbackWrapper::Done() {
    uv_mutex_lock(&mutex);
    uv_cond_signal(&cond);
    uv_mutex_unlock(&mutex);
}
void CallbackWrapper::Wait() {
    uv_cond_wait(&cond, &mutex);
}

};
<|endoftext|>


<commit_before>#pragma once

#include <experimental/string_view>
#include <string>
#include <vector>

#include "errors.hpp"

using std::experimental::string_view;
using std::string;
using std::vector;
<commit_msg>use non-experimental string_view implementation<commit_after>#pragma once

#include <string>
#include <string_view>
#include <vector>

#include "errors.hpp"

using std::string;
using std::string_view;
using std::vector;
<|endoftext|>


<commit_before>//
// Created by arrow on 9/21/16.
//

#include "autoconf.h"
#include "config.h"

#include <boost/program_options.hpp>
#include <iostream>
#include <cstdlib>

namespace po = boost::program_options;

namespace rethinkmud
{
    namespace config
    {
        void load(int argc, char* argv[])
        {
            po::options_description general{"General options"};
            general.add_options()
                ("help", "show help message")
                ("version", "show program version");

            po::variables_map vm;
            po::store(po::parse_command_line(argc, argv, general), vm, true);

            if (vm.count("help"))
            {
                std::cout << general << '\n';
                std::exit(0);
            }

            if (vm.count("version"))
            {
                std::cout << "RethinkMUD version " << RETHINKMUD_VERSION << '\n';
                std::exit(0);
            }
        }
    }
}
<commit_msg>Basic command-line argument handling<commit_after>//
// Created by arrow on 9/21/16.
//

#include "autoconf.h"
#include "config.h"

#include <boost/program_options.hpp>
#include <iostream>
#include <cstdlib>

namespace po = boost::program_options;

namespace rethinkmud
{
    namespace config
    {
        namespace
        {
            po::options_description get_command_line_options(std::string const &argv0)
            {
                std::string default_config_file = argv0 + ".cfg";

                po::options_description general{"General options"};
                general.add_options()
                    ("help,h", "show help message")
                    ("version,v", "show program version")
                    ("config,c", po::value<std::string>()->default_value(default_config_file), "configuration file");

                po::options_description options;
                return options.add(general);
            }
        }

        void load(int argc, char* argv[])
        {
            auto options = get_command_line_options(argv[0]);
            //auto config = get_config_options();
            //auto common = get_common_options();

            //options.add(common);
            //config.add(common);

            po::variables_map vm;

            try
            {
                po::store(po::parse_command_line(argc, argv, options), vm, true);
            }
            catch (po::error& e)
            {
                std::clog << "Error: " << e.what() << '\n';
                std::clog << "Error: Use '" << argv[0] << " --help' to get help about command line options\n";
                std::exit(1);
            }

            po::notify(vm);

            if (vm.count("help"))
            {
                std::cout << options << '\n';
                std::exit(0);
            }

            if (vm.count("version"))
            {
                std::cout << "RethinkMUD version " << RETHINKMUD_VERSION << '\n';
                std::exit(0);
            }

            std::cout << "Configuration file = " << vm["config"].as<std::string>() << '\n';

            //try
            //{
            //    po::store(po::parse_command_line(argc, argv, config), vm, true);
            //}
            //catch (po::error& e)
            //{
            //    std::clog << "Error: " << e.what() << '\n';
            //    std::exit(1);
            //}

        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chainparams.h"
#include "main.h"

#include "test/test_bitcoin.h"

#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)

static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
{
    int maxHalvings = 64;
    CAmount nInitialSubsidy = 50 * COIN;

    CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
    BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
    for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
        int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams, 1475020800);
        BOOST_CHECK(nSubsidy <= nInitialSubsidy);
        if(nHeight > 0)
            BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
        nPreviousSubsidy = nPreviousSubsidy / 2;
    }
    BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
}

static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
{
    Consensus::Params consensusParams;
    consensusParams.nMTPSwitchTime = INT_MAX;
    consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
    TestBlockSubsidyHalvings(consensusParams);
}

BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
    TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
    TestBlockSubsidyHalvings(305000); // As in regtest
    //TestBlockSubsidyHalvings(1000); // Just another interval
}

BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
    Consensus::Params consensusParams = Params(CBaseChainParams::MAIN).GetConsensus();
    CAmount nSum = 0;
    int const t5m = 300
        , t10m = 600
        , mtpActivationHeight = (consensusParams.nMTPSwitchTime - consensusParams.nChainStartTime) / t10m
        , mtpReleaseHeight = 110725
        ;

    int nHeight = 0;
    int const step = 1000;

    consensusParams.nSubsidyHalvingInterval = 210000;
    for(; nHeight < mtpReleaseHeight; nHeight += step)
    {
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
        if(nHeight == 0)
            nSubsidy = 50 * COIN;
        BOOST_CHECK(nSubsidy <= 50 * COIN);
        nSum += nSubsidy * 1000;
        BOOST_CHECK(MoneyRange(nSum));
    }
    BOOST_CHECK_EQUAL(nSum, 555000000000000ULL);

    consensusParams.nSubsidyHalvingInterval = 305000;
    for(; nHeight < 14000000 + mtpReleaseHeight; nHeight += step)
    {
        int blockTime = nHeight * t10m;
        if(nHeight > mtpActivationHeight)
            blockTime -= (nHeight - mtpActivationHeight) * t5m;

        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams, blockTime + consensusParams.nChainStartTime);
        if(nHeight == 0)
            nSubsidy = 50 * COIN;
        BOOST_CHECK(nSubsidy <= 50 * COIN);
        nSum += nSubsidy * 1000;
        BOOST_CHECK(MoneyRange(nSum));
    }
    BOOST_CHECK_EQUAL(nSum, 2003203125000000ULL);
}

bool ReturnFalse() { return false; }
bool ReturnTrue() { return true; }

BOOST_AUTO_TEST_CASE(test_combiner_all)
{
    boost::signals2::signal<bool (), CombinerAll> Test;
    BOOST_CHECK(Test());
    Test.connect(&ReturnFalse);
    BOOST_CHECK(!Test());
    Test.connect(&ReturnTrue);
    BOOST_CHECK(!Test());
    Test.disconnect(&ReturnFalse);
    BOOST_CHECK(Test());
    Test.disconnect(&ReturnTrue);
    BOOST_CHECK(Test());
}
BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Used the approximation for MTP switch height<commit_after>// Copyright (c) 2014-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chainparams.h"
#include "main.h"

#include "test/test_bitcoin.h"

#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)

static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
{
    int maxHalvings = 64;
    CAmount nInitialSubsidy = 50 * COIN;

    CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
    BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
    for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
        int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams, 1475020800);
        BOOST_CHECK(nSubsidy <= nInitialSubsidy);
        if(nHeight > 0)
            BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
        nPreviousSubsidy = nPreviousSubsidy / 2;
    }
    BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
}

static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
{
    Consensus::Params consensusParams;
    consensusParams.nMTPSwitchTime = INT_MAX;
    consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
    TestBlockSubsidyHalvings(consensusParams);
}

BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
    TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
    TestBlockSubsidyHalvings(305000); // As in regtest
    //TestBlockSubsidyHalvings(1000); // Just another interval
}

BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
    Consensus::Params consensusParams = Params(CBaseChainParams::MAIN).GetConsensus();
    CAmount nSum = 0;
    int const mtpReleaseHeight = 110725
        //The MTP switch time is December 10th at 12:00 UTC.
        //The block height of MTP switch cannot be calculated firmly, but can only be approximated.
        //Below is one of such approximations which is used for this test only.
        //This approximation influences the check at the end of the test.
        , mtpActivationHeight = 117560;

    int nHeight = 0;
    int step = 1;

    consensusParams.nSubsidyHalvingInterval = 210000;
    for(; nHeight < mtpReleaseHeight; nHeight += step)
    {
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
        if(nHeight == 0)
            nSubsidy = 50 * COIN;
        BOOST_CHECK(nSubsidy <= 50 * COIN);
        nSum += nSubsidy * step;
        BOOST_CHECK(MoneyRange(nSum));
    }
    BOOST_CHECK_EQUAL(nSum, 553625000000000ULL);

    consensusParams.nSubsidyHalvingInterval = 305000;
    for(; nHeight < mtpActivationHeight; nHeight += step)
    {
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= 50 * COIN);
        nSum += nSubsidy * step;
        BOOST_CHECK(MoneyRange(nSum));
    }
    BOOST_CHECK_EQUAL(nSum, 587800000000000ULL);

    step = 1000;
    for(; nHeight < 14000000; nHeight += step)
    {
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams, consensusParams.nMTPSwitchTime);
        BOOST_CHECK(nSubsidy <= 50 * COIN);
        nSum += nSubsidy * step;
        BOOST_CHECK(MoneyRange(nSum));
    }
    //The final check value is changed due to the approximation of mtpActivationHeight
    BOOST_CHECK_EQUAL(nSum, 1820299996645000ULL);
}

bool ReturnFalse() { return false; }
bool ReturnTrue() { return true; }

BOOST_AUTO_TEST_CASE(test_combiner_all)
{
    boost::signals2::signal<bool (), CombinerAll> Test;
    BOOST_CHECK(Test());
    Test.connect(&ReturnFalse);
    BOOST_CHECK(!Test());
    Test.connect(&ReturnTrue);
    BOOST_CHECK(!Test());
    Test.disconnect(&ReturnFalse);
    BOOST_CHECK(Test());
    Test.disconnect(&ReturnTrue);
    BOOST_CHECK(Test());
}
BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 The Bitsend Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chainparams.h"
#include "validation.h"
#include "net.h"

#include "test/test_bitsend.h"

#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)

static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
{
    int maxHalvings = 64;
    CAmount nInitialSubsidy = 50 * COIN;

    CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
    BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
    for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
        int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= nInitialSubsidy);
        BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
        nPreviousSubsidy = nSubsidy;
    }
    BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
}

static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
{
    Consensus::Params consensusParams;
    consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
    TestBlockSubsidyHalvings(consensusParams);
}

BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
    TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
    TestBlockSubsidyHalvings(150); // As in regtest
    TestBlockSubsidyHalvings(1000); // Just another interval
}

BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
    const Consensus::Params& consensusParams = Params(CBaseChainParams::MAIN).GetConsensus();
    CAmount nSum = 0;
	int nBits = 0;
    for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
        CAmount nSubsidy = GetBlockSubsidy(nBits, nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= 50 * COIN);
        nSum += nSubsidy * 1000;
        BOOST_CHECK(MoneyRange(nSum));
    }
    BOOST_CHECK_EQUAL(nSum, 2099999997690000ULL);
}

bool ReturnFalse() { return false; }
bool ReturnTrue() { return true; }

BOOST_AUTO_TEST_CASE(test_combiner_all)
{
    boost::signals2::signal<bool (), CombinerAll> Test;
    BOOST_CHECK(Test());
    Test.connect(&ReturnFalse);
    BOOST_CHECK(!Test());
    Test.connect(&ReturnTrue);
    BOOST_CHECK(!Test());
    Test.disconnect(&ReturnFalse);
    BOOST_CHECK(Test());
    Test.disconnect(&ReturnTrue);
    BOOST_CHECK(Test());
}
BOOST_AUTO_TEST_SUITE_END()
<commit_msg>test fix<commit_after>// Copyright (c) 2014-2016 The Bitsend Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chainparams.h"
#include "validation.h"
#include "net.h"

#include "test/test_bitsend.h"

#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)

static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
{
    int maxHalvings = 64;
    CAmount nInitialSubsidy = 50 * COIN;
	int nBits = 0;

    CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
    BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
    for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
        int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
        CAmount nSubsidy = GetBlockSubsidy(nBits, nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= nInitialSubsidy);
        BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
        nPreviousSubsidy = nSubsidy;
    }
    BOOST_CHECK_EQUAL(GetBlockSubsidy(nBits, maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
}

static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
{
    Consensus::Params consensusParams;
    consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
    TestBlockSubsidyHalvings(consensusParams);
}

BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
    TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
    TestBlockSubsidyHalvings(150); // As in regtest
    TestBlockSubsidyHalvings(1000); // Just another interval
}

BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
    const Consensus::Params& consensusParams = Params(CBaseChainParams::MAIN).GetConsensus();
    CAmount nSum = 0;
	int nBits = 0;
    for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
        CAmount nSubsidy = GetBlockSubsidy(nBits, nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= 50 * COIN);
        nSum += nSubsidy * 1000;
        BOOST_CHECK(MoneyRange(nSum));
    }
    BOOST_CHECK_EQUAL(nSum, 2099999997690000ULL);
}

bool ReturnFalse() { return false; }
bool ReturnTrue() { return true; }

BOOST_AUTO_TEST_CASE(test_combiner_all)
{
    boost::signals2::signal<bool (), CombinerAll> Test;
    BOOST_CHECK(Test());
    Test.connect(&ReturnFalse);
    BOOST_CHECK(!Test());
    Test.connect(&ReturnTrue);
    BOOST_CHECK(!Test());
    Test.disconnect(&ReturnFalse);
    BOOST_CHECK(Test());
    Test.disconnect(&ReturnTrue);
    BOOST_CHECK(Test());
}
BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: DAVSessionFactory.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: kso $ $Date: 2002-10-28 16:20:01 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _DAVSESSIONFACTORY_HXX_
#include "DAVSessionFactory.hxx"
#endif
#ifndef _NEONSESSION_HXX_
#include "NeonSession.hxx"
#endif
#ifndef _NEONURI_HXX_
#include "NeonUri.hxx"
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

using namespace webdav_ucp;
using namespace com::sun::star;

DAVSessionFactory::~DAVSessionFactory()
{
}

rtl::Reference< DAVSession > DAVSessionFactory::createDAVSession(
                const ::rtl::OUString & inUri,
                const uno::Reference< lang::XMultiServiceFactory > & rxSMgr )
    throw( DAVException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( !m_xProxyDecider.get() )
        m_xProxyDecider.reset( new ucbhelper::InternetProxyDecider( rxSMgr ) );

    Map::iterator aIt( m_aMap.begin() );
    Map::iterator aEnd( m_aMap.end() );

    while ( aIt != aEnd )
    {
        if ( (*aIt).second->CanUse( inUri ) )
            break;

        ++aIt;
    }

    if ( aIt == aEnd )
    {
        NeonUri aURI( inUri );

        std::auto_ptr< DAVSession > xElement(
            ( aURI.GetScheme().equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( "http" ) ) ||
             aURI.GetScheme().equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
            ? new NeonSession(
                this, inUri, m_xProxyDecider->getProxy( aURI.GetScheme(),
                                                        aURI.GetHost(),
                                                        aURI.GetPort() ) )
            : new NeonSession(
                this, inUri, m_xProxyDecider->getProxy( aURI.GetScheme(),
                                                        rtl::OUString() /* not used */,
                                                        -1 /* not used */ ) ) );
        aIt = m_aMap.insert( Map::value_type( inUri, xElement.get() ) ).first;
        aIt->second->m_aContainerIt = aIt;
        xElement.release();
        return aIt->second;
    }
    else if ( osl_incrementInterlockedCount( &aIt->second->m_nRefCount ) > 1 )
    {
        rtl::Reference< DAVSession > xElement( aIt->second );
        osl_decrementInterlockedCount( &aIt->second->m_nRefCount );
        return xElement;
    }
    else
    {
        osl_decrementInterlockedCount( &aIt->second->m_nRefCount );
        aIt->second->m_aContainerIt = m_aMap.end();

        // If URL scheme is different from http or https we definitely
        // have to use a proxy and therefore can optimize the getProxy
        // call a little:
        NeonUri aURI( inUri );

        if ( aURI.GetScheme().equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( "http" ) ) ||
             aURI.GetScheme().equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
            aIt->second = new NeonSession( this,
                                           inUri,
                                           m_xProxyDecider->getProxy(
                                            aURI.GetScheme(),
                                            aURI.GetHost(),
                                            aURI.GetPort() ) );
        else
            aIt->second = new NeonSession( this,
                                           inUri,
                                           m_xProxyDecider->getProxy(
                                            aURI.GetScheme(),
                                            rtl::OUString() /* not used */,
                                            -1 /* not used */ ) );
        aIt->second->m_aContainerIt = aIt;
        return aIt->second;
    }
}

void DAVSessionFactory::releaseElement( DAVSession * pElement ) SAL_THROW(())
{
    OSL_ASSERT( pElement );
    osl::MutexGuard aGuard( m_aMutex );
    if ( pElement->m_aContainerIt != m_aMap.end() )
        m_aMap.erase( pElement->m_aContainerIt );
}

<commit_msg>INTEGRATION: CWS kso9 (1.9.124); FILE MERGED 2004/02/25 10:26:54 kso 1.9.124.1: #112271# - Handle runtime changes of proxy configuration.<commit_after>/*************************************************************************
 *
 *  $RCSfile: DAVSessionFactory.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: obo $ $Date: 2004-03-17 11:24:55 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _DAVSESSIONFACTORY_HXX_
#include "DAVSessionFactory.hxx"
#endif
#ifndef _NEONSESSION_HXX_
#include "NeonSession.hxx"
#endif
#ifndef _NEONURI_HXX_
#include "NeonUri.hxx"
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

using namespace webdav_ucp;
using namespace com::sun::star;

DAVSessionFactory::~DAVSessionFactory()
{
}

rtl::Reference< DAVSession > DAVSessionFactory::createDAVSession(
                const ::rtl::OUString & inUri,
                const uno::Reference< lang::XMultiServiceFactory > & rxSMgr )
    throw( DAVException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( !m_xProxyDecider.get() )
        m_xProxyDecider.reset( new ucbhelper::InternetProxyDecider( rxSMgr ) );

    Map::iterator aIt( m_aMap.begin() );
    Map::iterator aEnd( m_aMap.end() );

    while ( aIt != aEnd )
    {
        if ( (*aIt).second->CanUse( inUri ) )
            break;

        ++aIt;
    }

    if ( aIt == aEnd )
    {
        NeonUri aURI( inUri );

        std::auto_ptr< DAVSession > xElement(
            new NeonSession( this, inUri, *m_xProxyDecider.get() ) );

        aIt = m_aMap.insert( Map::value_type( inUri, xElement.get() ) ).first;
        aIt->second->m_aContainerIt = aIt;
        xElement.release();
        return aIt->second;
    }
    else if ( osl_incrementInterlockedCount( &aIt->second->m_nRefCount ) > 1 )
    {
        rtl::Reference< DAVSession > xElement( aIt->second );
        osl_decrementInterlockedCount( &aIt->second->m_nRefCount );
        return xElement;
    }
    else
    {
        osl_decrementInterlockedCount( &aIt->second->m_nRefCount );
        aIt->second->m_aContainerIt = m_aMap.end();

        // If URL scheme is different from http or https we definitely
        // have to use a proxy and therefore can optimize the getProxy
        // call a little:
        NeonUri aURI( inUri );

        aIt->second = new NeonSession( this, inUri, *m_xProxyDecider.get() );
        aIt->second->m_aContainerIt = aIt;
        return aIt->second;
    }
}

void DAVSessionFactory::releaseElement( DAVSession * pElement ) SAL_THROW(())
{
    OSL_ASSERT( pElement );
    osl::MutexGuard aGuard( m_aMutex );
    if ( pElement->m_aContainerIt != m_aMap.end() )
        m_aMap.erase( pElement->m_aContainerIt );
}

<|endoftext|>


<commit_before>// Copyright (c) 2012 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 "ui/base/resource/resource_bundle.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_handle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/display.h"
#include "ui/gfx/image/image.h"

namespace {

FilePath GetResourcesPakFilePath(const std::string& pak_name) {
  FilePath path;
  if (PathService::Get(base::DIR_MODULE, &path))
    return path.AppendASCII(pak_name.c_str());

  // Return just the name of the pack file.
  return FilePath(pak_name.c_str());
}

}  // namespace

namespace ui {

void ResourceBundle::LoadCommonResources() {
  // Always load the 1x data pack first as the 2x data pack contains both 1x and
  // 2x images. The 1x data pack only has 1x images, thus passes in an accurate
  // scale factor to gfx::ImageSkia::AddRepresentation.

  AddDataPackFromPath(GetResourcesPakFilePath("chrome.pak"),
                      SCALE_FACTOR_100P);
  AddDataPackFromPath(GetResourcesPakFilePath(
                      "chrome_100_percent.pak"),
                      SCALE_FACTOR_100P);
  AddOptionalDataPackFromPath(GetResourcesPakFilePath(
                              "chrome_200_percent.pak"),
                              SCALE_FACTOR_200P);
}

gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) {
  // Flipped image is not used on ChromeOS.
  DCHECK_EQ(rtl, RTL_DISABLED);
  return GetImageNamed(resource_id);
}

}  // namespace ui
<commit_msg>Desktop linux aura: Don't search for chrome_200_percent.pak.<commit_after>// Copyright (c) 2012 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 "ui/base/resource/resource_bundle.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_handle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/display.h"
#include "ui/gfx/image/image.h"

namespace {

FilePath GetResourcesPakFilePath(const std::string& pak_name) {
  FilePath path;
  if (PathService::Get(base::DIR_MODULE, &path))
    return path.AppendASCII(pak_name.c_str());

  // Return just the name of the pack file.
  return FilePath(pak_name.c_str());
}

}  // namespace

namespace ui {

void ResourceBundle::LoadCommonResources() {
  // Always load the 1x data pack first as the 2x data pack contains both 1x and
  // 2x images. The 1x data pack only has 1x images, thus passes in an accurate
  // scale factor to gfx::ImageSkia::AddRepresentation.

  AddDataPackFromPath(GetResourcesPakFilePath("chrome.pak"),
                      SCALE_FACTOR_100P);
  AddDataPackFromPath(GetResourcesPakFilePath(
      "chrome_100_percent.pak"), SCALE_FACTOR_100P);

  if (ui::IsScaleFactorSupported(SCALE_FACTOR_200P)) {
    AddOptionalDataPackFromPath(GetResourcesPakFilePath(
        "chrome_200_percent.pak"), SCALE_FACTOR_200P);
  }
}

gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) {
  // Flipped image is not used on ChromeOS.
  DCHECK_EQ(rtl, RTL_DISABLED);
  return GetImageNamed(resource_id);
}

}  // namespace ui
<|endoftext|>


<commit_before>#include "swift/Syntax/ExprSyntax.h"
#include "swift/Syntax/SyntaxFactory.h"
#include "swift/Syntax/StmtSyntax.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"

#include <future>
#include <thread>
#include <queue>

using namespace swift;
using namespace swift::syntax;

static uintptr_t getExpressionFrom(ReturnStmtSyntax Return) {
  auto Expression = Return.getExpression().getValue();
  return reinterpret_cast<uintptr_t>(Expression.getDataPointer());
}

class Pool {
  static constexpr size_t NumThreads = 2;
  using FuncTy = std::function<uintptr_t(ReturnStmtSyntax)>;
  std::vector<std::thread> Workers;
  std::queue<std::function<void()>> Tasks;
  std::mutex QueueLock;
  std::condition_variable Condition;
  bool Stop;

public:
  Pool() : Stop(false) {
    for(size_t i = 0; i < NumThreads; ++i)
      Workers.emplace_back([this] {
        while (true) {
          std::function<void()> Task;
          {
            std::unique_lock<std::mutex> L(QueueLock);

            Condition.wait(L, [this]{
              return Stop || !Tasks.empty();
            });

            if(Stop && Tasks.empty()) {
              return;
            }

            Task = std::move(Tasks.front());
            Tasks.pop();
          }

          Task();
        }
      });
  }

  std::future<uintptr_t> run(FuncTy Func, ReturnStmtSyntax Return) {
    auto Task = std::make_shared<std::packaged_task<uintptr_t()>>(
      std::bind(Func, Return));

    auto Future = Task->get_future();
    {
      std::unique_lock<std::mutex> L(QueueLock);
      Tasks.emplace([Task](){ (*Task)(); });
    }
    Condition.notify_one();
    return Future;
  }

  ~Pool() {
    {
      std::lock_guard<std::mutex> L(QueueLock);
      Stop = true;
    }
    Condition.notify_all();
    for(auto &Worker : Workers) {
      Worker.join();
    }
  }
};

// Tests that, when multiple threads ask for a child node of the same syntax
// node:
// - Only one thread inserts the realized child into the parent
// - Both threads get the exact same child (by identity)
TEST(ThreadSafeCachingTests, ReturnGetExpression) {
#if 0
  auto ReturnKW = SyntaxFactory::makeReturnKeyword({}, Trivia::spaces(1));
  auto Minus = SyntaxFactory::makePrefixOpereator("-", {});
  auto One = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
  auto MinusOne = SyntaxFactory::makeIntegerLiteralExpr(Minus, One);

  Pool P;

  for (unsigned i = 0; i < 10000; ++i) {
    auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);

    auto Future1 = P.run(getExpressionFrom, Return);
    auto Future2 = P.run(getExpressionFrom, Return);

    auto FirstDataPointer = Future1.get();
    auto SecondDataPointer = Future2.get();

    auto DataPointer = reinterpret_cast<uintptr_t>(
      Return.getExpression().getValue().getDataPointer());

    ASSERT_EQ(FirstDataPointer, SecondDataPointer);
    ASSERT_EQ(FirstDataPointer, DataPointer);
  }
#endif
}

<commit_msg>[Syntax] Reenable thread-safe caching test<commit_after>#include "swift/Syntax/ExprSyntax.h"
#include "swift/Syntax/SyntaxFactory.h"
#include "swift/Syntax/StmtSyntax.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"

#include <future>
#include <thread>
#include <queue>

using namespace swift;
using namespace swift::syntax;

static uintptr_t getExpressionFrom(ReturnStmtSyntax Return) {
  auto Expression = Return.getExpression().getValue();
  return reinterpret_cast<uintptr_t>(Expression.getDataPointer());
}

class Pool {
  static constexpr size_t NumThreads = 2;
  using FuncTy = std::function<uintptr_t(ReturnStmtSyntax)>;
  std::vector<std::thread> Workers;
  std::queue<std::function<void()>> Tasks;
  std::mutex QueueLock;
  std::condition_variable Condition;
  bool Stop;

public:
  Pool() : Stop(false) {
    for(size_t i = 0; i < NumThreads; ++i)
      Workers.emplace_back([this] {
        while (true) {
          std::function<void()> Task;
          {
            std::unique_lock<std::mutex> L(QueueLock);

            Condition.wait(L, [this]{
              return Stop || !Tasks.empty();
            });

            if(Stop && Tasks.empty()) {
              return;
            }

            Task = std::move(Tasks.front());
            Tasks.pop();
          }

          Task();
        }
      });
  }

  std::future<uintptr_t> run(FuncTy Func, ReturnStmtSyntax Return) {
    auto Task = std::make_shared<std::packaged_task<uintptr_t()>>(
      std::bind(Func, Return));

    auto Future = Task->get_future();
    {
      std::unique_lock<std::mutex> L(QueueLock);
      Tasks.emplace([Task](){ (*Task)(); });
    }
    Condition.notify_one();
    return Future;
  }

  ~Pool() {
    {
      std::lock_guard<std::mutex> L(QueueLock);
      Stop = true;
    }
    Condition.notify_all();
    for(auto &Worker : Workers) {
      Worker.join();
    }
  }
};

// Tests that, when multiple threads ask for a child node of the same syntax
// node:
// - Only one thread inserts the realized child into the parent
// - Both threads get the exact same child (by identity)
TEST(ThreadSafeCachingTests, ReturnGetExpression) {
  auto ReturnKW = SyntaxFactory::makeReturnKeyword({}, Trivia::spaces(1));
  auto Minus = SyntaxFactory::makePrefixOpereator("-", {});
  auto One = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
  auto MinusOne = SyntaxFactory::makeIntegerLiteralExpr(Minus, One);

  Pool P;

  for (unsigned i = 0; i < 10000; ++i) {
    auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);

    auto Future1 = P.run(getExpressionFrom, Return);
    auto Future2 = P.run(getExpressionFrom, Return);

    auto FirstDataPointer = Future1.get();
    auto SecondDataPointer = Future2.get();

    auto DataPointer = reinterpret_cast<uintptr_t>(
      Return.getExpression().getValue().getDataPointer());

    ASSERT_EQ(FirstDataPointer, SecondDataPointer);
    ASSERT_EQ(FirstDataPointer, DataPointer);
  }
}

<|endoftext|>


<commit_before>#include "darklyricssite.h"
#include "shared.h"
#include <QDebug>
#include <QRegularExpression>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>

DarkLyricsSite::DarkLyricsSite() {
}

void DarkLyricsSite::fetchLyrics(const QString &artist, const QString &title, std::function<void (const QString &, FetchResult)> callback) {
    QString simplifiedArtist = simplifiedRepresentation(artist);
    QString simplifiedTitle = simplifiedRepresentation(title);

    if (nonExistentArtistCache.contains(simplifiedArtist)) {
        // We need to check this, so that we don't request the same page dozens or even hundreds of times,
        // only to get a HTTP 404 every single time.
        callback({}, FetchResult::NoMatch);
        return;
    }

    // We use two levels of caching for DarkLyrics.
    // The more basic one is a map between <artist, title> pairs and the URL to the lyrics page, as for the other sites.
    // However, DarkLyrics has all the lyrics for an entire album on a single page, which means it's a waste to fetch the same page
    // multiple times, in case we're requesting lyrics for multiple songs on a single album.
    // We begin by looking in a cache that stores lyrics for songs that the parser has already seen, either because that song was requested previously,
    // or because a different song from the same album was requested previously.
    if (lyricsCache.contains({simplifiedArtist, simplifiedTitle})) {
        // Wohoo!
        callback(lyricsCache[{simplifiedArtist, simplifiedTitle}], FetchResult::Success);
        return;
    }

    // OK, so the faster cache failed; let's try the second-best thing.
    if (titleURLCache.contains({simplifiedArtist, simplifiedTitle})) {
        QUrl url = titleURLCache[{simplifiedArtist, simplifiedTitle}];
        qDebug() << "URL was cached!" << artist << "-" << title << "==>" << url;
        QNetworkRequest networkRequest(url);
        QNetworkReply *reply = accessManager.get(networkRequest);
        QObject::connect(reply, &QNetworkReply::finished, [=] {
            lyricsPageResponseHandler(artist, title, callback, reply);
        });

        return;
    }

    // If we get here, the URL wasn't cached, and so we need to start at the beginning.

    QString artistURL;
    FetchResult result;
    std::tie(artistURL, result) = getArtistURL(artist);
    if (artistURL.length() < 1 || result != FetchResult::Success) {
        callback({}, result);
        return;
    }

    // Time to figure out the track URL. We need to fetch the artist page to do that,
    // which means we need to use some asynchronous programming, due to the QNAM API.
    QNetworkRequest networkRequest((QUrl(artistURL)));
    QNetworkReply *reply = accessManager.get(networkRequest);
    QObject::connect(reply, &QNetworkReply::finished, [=] {
        artistPageResponseHandler(artist, title, callback, reply);
    });
}

std::tuple<QString, FetchResult> DarkLyricsSite::getArtistURL(const QString &_artist) const {
    // These URLs have a simple format, so we can figure them out instead of having to
    // fetch and parse HTML. Nice and speedy!
    //
    // We begin with stripping everything but regular characters, including whitespace, and convert to lowercase.
    // E.g. "Dream Theater" -> "dreamtheater"
    QString artist = _artist;
    artist = artist.toLower().replace(QRegularExpression("[^A-Za-z0-9]"), "");

    if (artist.length() < 1)
        return std::make_tuple(QString(), FetchResult::InvalidRequest);

    if (artist[0].isDigit())
        return std::make_tuple(QString("http://www.darklyrics.com/19/%1.html").arg(artist), FetchResult::Success);
    else
        return std::make_tuple(QString("http://www.darklyrics.com/%1/%2.html").arg(QString(artist[0]), artist), FetchResult::Success);
}

void DarkLyricsSite::artistPageResponseHandler(const QString &artist, const QString &title, std::function<void (const QString &, FetchResult)> callback, QNetworkReply *reply) {
    reply->deleteLater();
    if (reply->error()) {
        if (reply->error() == QNetworkReply::ContentNotFoundError) {
            // We didn't ask anyone if this artist existed at DarkLyrics -- we assumed. If it didn't, that's not really an error that
            // we should show in red to the user, so we return no match instead.
            nonExistentArtistCache.append(simplifiedRepresentation(artist));
            callback(QString(), FetchResult::NoMatch);
        }
        else
            callback(QString(), FetchResult::RequestFailed); // TODO: use more specific errors

        return;
    }

    QString receivedHTML = QString(reply->readAll());
    QRegularExpression re(R"##((.*?)
)##");
    QRegularExpressionMatchIterator matchIterator = re.globalMatch(receivedHTML);

    QString simplifiedArtist = simplifiedRepresentation(artist);
    QString simplifiedTitle = simplifiedRepresentation(title);
    while (matchIterator.hasNext()) {
        QRegularExpressionMatch match = matchIterator.next();
        QString url = "http://www.darklyrics.com/" + match.captured(1);
        QString foundTitle = simplifiedRepresentation(match.captured(2));
        titleURLCache[{simplifiedArtist, foundTitle}] = QUrl(url);
    }

    if (titleURLCache.contains({simplifiedArtist, simplifiedTitle})) {
        QUrl url = titleURLCache[{simplifiedArtist, simplifiedTitle}];

        // Okay! We have the final URL; we need to fetch it, followed by "parsing" it (with regular expressions,
        // since that works well in practice -- no need to actually parse with a proper HTML parser).
        QNetworkRequest networkRequest(url);
        QNetworkReply *reply = accessManager.get(networkRequest);
        QObject::connect(reply, &QNetworkReply::finished, [=] {
            lyricsPageResponseHandler(artist, title, callback, reply);
        });

        return;
    }

    callback({}, FetchResult::NoMatch);
}

void DarkLyricsSite::lyricsPageResponseHandler(const QString &artist, const QString &title, std::function<void (const QString &, FetchResult)> callback, QNetworkReply *reply) {
    reply->deleteLater();
    if (reply->error()) {
        callback(QString(), FetchResult::RequestFailed); // TODO: use more specific errors
        return;
    }

    QString receivedHTML = QString(reply->readAll());
    QRegularExpression re(R"##(
\d+\. ([^<]*?)

\s*([\s\S]+?)(?=

))##");
    re.setPatternOptions(re.patternOptions() | QRegularExpression::CaseInsensitiveOption);
    QRegularExpressionMatchIterator matchIterator = re.globalMatch(receivedHTML, 0, QRegularExpression::NormalMatch);

    // DarkLyrics stores all the lyrics for an album on a single page, so if we want to fetch all the lyrics for an album,
    // we can use a cache to fetch them exactly once, instead of once per track.
    // We parse the entire page on the first call, since storing the HTML would use more memory.
    QString simplifiedArtist = simplifiedRepresentation(artist);
    QString simplifiedTitle = simplifiedRepresentation(title);
    while (matchIterator.hasNext()) {
        QRegularExpressionMatch match = matchIterator.next();
        QString foundTitle = simplifiedRepresentation(match.captured(1));
        QString foundLyrics = match.captured(2).replace(QRegularExpression("<[^>]*>"), ""); // Remove HTML tags
        foundLyrics = foundLyrics.replace(QRegularExpression("\\A\\s+|\\s+\\Z"), ""); // Trim whitespace from beginning and end
        lyricsCache[{simplifiedArtist, foundTitle}] = foundLyrics;
    }

    // Finally, use the cache to actually look up the lyrics we wanted to fetch in the first place.
    if (lyricsCache.contains({simplifiedArtist, simplifiedTitle})) {
        callback(lyricsCache[{simplifiedArtist, simplifiedTitle}], FetchResult::Success);
        return;
    }

    // If we get here, something likely went wrong. We KNOW that the lyrics for this track should be on this page,
    // since we got here from the artist page, which lists all the tracks.
    // Therefore, this most likely happened because of a parsing error, e.g. because the site has been updated such
    // that the regex no longer matches correctly.
    callback({}, FetchResult::ParsingFailed);
}
<commit_msg>Fix parsing for DarkLyrics where lyrics are said to exist, but are actually empty on the page<commit_after>#include "darklyricssite.h"
#include "shared.h"
#include <QDebug>
#include <QRegularExpression>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>

DarkLyricsSite::DarkLyricsSite() {
}

void DarkLyricsSite::fetchLyrics(const QString &artist, const QString &title, std::function<void (const QString &, FetchResult)> callback) {
    QString simplifiedArtist = simplifiedRepresentation(artist);
    QString simplifiedTitle = simplifiedRepresentation(title);

    if (nonExistentArtistCache.contains(simplifiedArtist)) {
        // We need to check this, so that we don't request the same page dozens or even hundreds of times,
        // only to get a HTTP 404 every single time.
        callback({}, FetchResult::NoMatch);
        return;
    }

    // We use two levels of caching for DarkLyrics.
    // The more basic one is a map between <artist, title> pairs and the URL to the lyrics page, as for the other sites.
    // However, DarkLyrics has all the lyrics for an entire album on a single page, which means it's a waste to fetch the same page
    // multiple times, in case we're requesting lyrics for multiple songs on a single album.
    // We begin by looking in a cache that stores lyrics for songs that the parser has already seen, either because that song was requested previously,
    // or because a different song from the same album was requested previously.
    if (lyricsCache.contains({simplifiedArtist, simplifiedTitle})) {
        // Wohoo!
        callback(lyricsCache[{simplifiedArtist, simplifiedTitle}], FetchResult::Success);
        return;
    }

    // OK, so the faster cache failed; let's try the second-best thing.
    if (titleURLCache.contains({simplifiedArtist, simplifiedTitle})) {
        QUrl url = titleURLCache[{simplifiedArtist, simplifiedTitle}];
        qDebug() << "URL was cached!" << artist << "-" << title << "==>" << url;
        QNetworkRequest networkRequest(url);
        QNetworkReply *reply = accessManager.get(networkRequest);
        QObject::connect(reply, &QNetworkReply::finished, [=] {
            lyricsPageResponseHandler(artist, title, callback, reply);
        });

        return;
    }

    // If we get here, the URL wasn't cached, and so we need to start at the beginning.

    QString artistURL;
    FetchResult result;
    std::tie(artistURL, result) = getArtistURL(artist);
    if (artistURL.length() < 1 || result != FetchResult::Success) {
        callback({}, result);
        return;
    }

    // Time to figure out the track URL. We need to fetch the artist page to do that,
    // which means we need to use some asynchronous programming, due to the QNAM API.
    QNetworkRequest networkRequest((QUrl(artistURL)));
    QNetworkReply *reply = accessManager.get(networkRequest);
    QObject::connect(reply, &QNetworkReply::finished, [=] {
        artistPageResponseHandler(artist, title, callback, reply);
    });
}

std::tuple<QString, FetchResult> DarkLyricsSite::getArtistURL(const QString &_artist) const {
    // These URLs have a simple format, so we can figure them out instead of having to
    // fetch and parse HTML. Nice and speedy!
    //
    // We begin with stripping everything but regular characters, including whitespace, and convert to lowercase.
    // E.g. "Dream Theater" -> "dreamtheater"
    QString artist = _artist;
    artist = artist.toLower().replace(QRegularExpression("[^A-Za-z0-9]"), "");

    if (artist.length() < 1)
        return std::make_tuple(QString(), FetchResult::InvalidRequest);

    if (artist[0].isDigit())
        return std::make_tuple(QString("http://www.darklyrics.com/19/%1.html").arg(artist), FetchResult::Success);
    else
        return std::make_tuple(QString("http://www.darklyrics.com/%1/%2.html").arg(QString(artist[0]), artist), FetchResult::Success);
}

void DarkLyricsSite::artistPageResponseHandler(const QString &artist, const QString &title, std::function<void (const QString &, FetchResult)> callback, QNetworkReply *reply) {
    reply->deleteLater();
    if (reply->error()) {
        if (reply->error() == QNetworkReply::ContentNotFoundError) {
            // We didn't ask anyone if this artist existed at DarkLyrics -- we assumed. If it didn't, that's not really an error that
            // we should show in red to the user, so we return no match instead.
            nonExistentArtistCache.append(simplifiedRepresentation(artist));
            callback(QString(), FetchResult::NoMatch);
        }
        else
            callback(QString(), FetchResult::RequestFailed); // TODO: use more specific errors

        return;
    }

    QString receivedHTML = QString(reply->readAll());
    QRegularExpression re(R"##((.*?)
)##");
    QRegularExpressionMatchIterator matchIterator = re.globalMatch(receivedHTML);

    QString simplifiedArtist = simplifiedRepresentation(artist);
    QString simplifiedTitle = simplifiedRepresentation(title);
    while (matchIterator.hasNext()) {
        QRegularExpressionMatch match = matchIterator.next();
        QString url = "http://www.darklyrics.com/" + match.captured(1);
        QString foundTitle = simplifiedRepresentation(match.captured(2));
        titleURLCache[{simplifiedArtist, foundTitle}] = QUrl(url);
    }

    if (titleURLCache.contains({simplifiedArtist, simplifiedTitle})) {
        QUrl url = titleURLCache[{simplifiedArtist, simplifiedTitle}];

        // Okay! We have the final URL; we need to fetch it, followed by "parsing" it (with regular expressions,
        // since that works well in practice -- no need to actually parse with a proper HTML parser).
        QNetworkRequest networkRequest(url);
        QNetworkReply *reply = accessManager.get(networkRequest);
        QObject::connect(reply, &QNetworkReply::finished, [=] {
            lyricsPageResponseHandler(artist, title, callback, reply);
        });

        return;
    }

    callback({}, FetchResult::NoMatch);
}

void DarkLyricsSite::lyricsPageResponseHandler(const QString &artist, const QString &title, std::function<void (const QString &, FetchResult)> callback, QNetworkReply *reply) {
    reply->deleteLater();
    if (reply->error()) {
        callback(QString(), FetchResult::RequestFailed); // TODO: use more specific errors
        return;
    }

    QString receivedHTML = QString(reply->readAll());
    QRegularExpression re(R"##(
\d+\. ([^<]*?)

\s*([\s\S]*?)(?=

))##");
    re.setPatternOptions(re.patternOptions() | QRegularExpression::CaseInsensitiveOption);
    QRegularExpressionMatchIterator matchIterator = re.globalMatch(receivedHTML, 0, QRegularExpression::NormalMatch);

    // DarkLyrics stores all the lyrics for an album on a single page, so if we want to fetch all the lyrics for an album,
    // we can use a cache to fetch them exactly once, instead of once per track.
    // We parse the entire page on the first call, since storing the HTML would use more memory.
    QString simplifiedArtist = simplifiedRepresentation(artist);
    QString simplifiedTitle = simplifiedRepresentation(title);
    while (matchIterator.hasNext()) {
        QRegularExpressionMatch match = matchIterator.next();
        QString foundTitle = simplifiedRepresentation(match.captured(1));
        QString foundLyrics = match.captured(2).replace(QRegularExpression("<[^>]*>"), ""); // Remove HTML tags
        foundLyrics = foundLyrics.replace(QRegularExpression("\\A\\s+|\\s+\\Z"), ""); // Trim whitespace from beginning and end
        lyricsCache[{simplifiedArtist, foundTitle}] = foundLyrics;
    }

    // Finally, use the cache to actually look up the lyrics we wanted to fetch in the first place.
    if (lyricsCache.contains({simplifiedArtist, simplifiedTitle})) {
        QString lyrics = lyricsCache[{simplifiedArtist, simplifiedTitle}];
        if (lyrics.length() > 0)
            callback(lyricsCache[{simplifiedArtist, simplifiedTitle}], FetchResult::Success);
        else
            callback({}, FetchResult::NoMatch);
        return;
    }

    // If we get here, something likely went wrong. We KNOW that the lyrics for this track should be on this page,
    // since we got here from the artist page, which lists all the tracks.
    // Therefore, this most likely happened because of a parsing error, e.g. because the site has been updated such
    // that the regex no longer matches correctly.
    callback({}, FetchResult::ParsingFailed);
}
<|endoftext|>


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

#include "Precompiled.h"
#include "Context.h"
#include "CoreEvents.h"
#include "File.h"
#include "IOEvents.h"
#include "Log.h"
#include "Mutex.h"
#include "ProcessUtils.h"
#include "Thread.h"
#include "Timer.h"

#include <cstdio>

#ifdef ANDROID
#include <android/log.h>
#endif
#ifdef IOS
extern "C" void SDL_IOS_LogMessage(const char* message);
#endif

#include "DebugNew.h"

namespace Urho3D
{

const char* logLevelPrefixes[] =
{
    "DEBUG",
    "INFO",
    "WARNING",
    "ERROR",
    0
};

static Log* logInstance = 0;

Log::Log(Context* context) :
    Object(context),
#ifdef _DEBUG
    level_(LOG_DEBUG),
#else
    level_(LOG_INFO),
#endif
    timeStamp_(true),
    inWrite_(false),
    quiet_(false)
{
    logInstance = this;

    SubscribeToEvent(E_ENDFRAME, HANDLER(Log, HandleEndFrame));
}

Log::~Log()
{
    logInstance = 0;
}

void Log::Open(const String& fileName)
{
    #if !defined(ANDROID) && !defined(IOS)
    if (fileName.Empty())
        return;
    if (logFile_ && logFile_->IsOpen())
    {
        if (logFile_->GetName() == fileName)
            return;
        else
            Close();
    }

    logFile_ = new File(context_);
    if (logFile_->Open(fileName, FILE_WRITE))
        Write(LOG_INFO, "Opened log file " + fileName);
    else
    {
        logFile_.Reset();
        Write(LOG_ERROR, "Failed to create log file " + fileName);
    }
    #endif
}

void Log::Close()
{
    #if !defined(ANDROID) && !defined(IOS)
    if (logFile_ && logFile_->IsOpen())
    {
        logFile_->Close();
        logFile_.Reset();
    }
    #endif
}

void Log::SetLevel(int level)
{
    assert(level >= LOG_DEBUG && level < LOG_NONE);

    level_ = level;
}

void Log::SetTimeStamp(bool enable)
{
    timeStamp_ = enable;
}

void Log::SetQuiet(bool quiet)
{
    quiet_ = quiet;
}

void Log::Write(int level, const String& message)
{
    assert(level >= LOG_DEBUG && level < LOG_NONE);

    // If not in the main thread, store message for later processing
    if (!Thread::IsMainThread())
    {
        if (logInstance)
        {
            MutexLock lock(logInstance->logMutex_);
            logInstance->threadMessages_.Push(StoredLogMessage(message, level, false));
        }

        return;
    }

    // Do not log if message level excluded or if currently sending a log event
    if (!logInstance || logInstance->level_ > level || logInstance->inWrite_)
        return;

    String formattedMessage = logLevelPrefixes[level];
    formattedMessage += ": " + message;
    logInstance->lastMessage_ = message;

    if (logInstance->timeStamp_)
        formattedMessage = "[" + Time::GetTimeStamp() + "] " + formattedMessage;

    #if defined(ANDROID)
    int androidLevel = ANDROID_LOG_DEBUG + level;
    __android_log_print(androidLevel, "Urho3D", "%s", message.CString());
    #elif defined(IOS)
    SDL_IOS_LogMessage(message.CString());
    #else
    if (logInstance->quiet_)
    {
        // If in quiet mode, still print the error message to the standard error stream
        if (level == LOG_ERROR)
            PrintUnicodeLine(formattedMessage, true);
    }
    else
        PrintUnicodeLine(formattedMessage, level == LOG_ERROR);
    #endif

    if (logInstance->logFile_)
    {
        logInstance->logFile_->WriteLine(formattedMessage);
        logInstance->logFile_->Flush();
    }

    logInstance->inWrite_ = true;

    using namespace LogMessage;

    VariantMap& eventData = logInstance->GetEventDataMap();
    eventData[P_MESSAGE] = formattedMessage;
    eventData[P_LEVEL] = level;
    logInstance->SendEvent(E_LOGMESSAGE, eventData);

    logInstance->inWrite_ = false;
}

void Log::WriteRaw(const String& message, bool error)
{
    // If not in the main thread, store message for later processing
    if (!Thread::IsMainThread())
    {
        if (logInstance)
        {
            MutexLock lock(logInstance->logMutex_);
            logInstance->threadMessages_.Push(StoredLogMessage(message, LOG_RAW, error));
        }

        return;
    }

    // Prevent recursion during log event
    if (!logInstance || logInstance->inWrite_)
        return;

    logInstance->lastMessage_ = message;

    #if defined(ANDROID)
    if (logInstance->quiet_)
    {
        if (error)
            __android_log_print(ANDROID_LOG_ERROR, "Urho3D", message.CString());
    }
    else
        __android_log_print(error ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "Urho3D", message.CString());
    #elif defined(IOS)
    SDL_IOS_LogMessage(message.CString());
    #else
    if (logInstance->quiet_)
    {
        // If in quiet mode, still print the error message to the standard error stream
        if (error)
            PrintUnicode(message, true);
    }
    else
        PrintUnicode(message, error);
    #endif

    if (logInstance->logFile_)
    {
        logInstance->logFile_->Write(message.CString(), message.Length());
        logInstance->logFile_->Flush();
    }

    logInstance->inWrite_ = true;

    using namespace LogMessage;

    VariantMap& eventData = logInstance->GetEventDataMap();
    eventData[P_MESSAGE] = message;
    eventData[P_LEVEL] = error ? LOG_ERROR : LOG_INFO;
    logInstance->SendEvent(E_LOGMESSAGE, eventData);

    logInstance->inWrite_ = false;
}

void Log::HandleEndFrame(StringHash eventType, VariantMap& eventData)
{
    MutexLock lock(logMutex_);

    // Process messages accumulated from other threads (if any)
    while (!threadMessages_.Empty())
    {
        const StoredLogMessage& stored = threadMessages_.Front();

        if (stored.level_ != LOG_RAW)
            Write(stored.level_, stored.message_);
        else
            WriteRaw(stored.message_, stored.error_);

        threadMessages_.PopFront();
    }
}

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

#include "Precompiled.h"
#include "Context.h"
#include "CoreEvents.h"
#include "File.h"
#include "IOEvents.h"
#include "Log.h"
#include "Mutex.h"
#include "ProcessUtils.h"
#include "Thread.h"
#include "Timer.h"

#include <cstdio>

#ifdef ANDROID
#include <android/log.h>
#endif
#ifdef IOS
extern "C" void SDL_IOS_LogMessage(const char* message);
#endif

#include "DebugNew.h"

namespace Urho3D
{

const char* logLevelPrefixes[] =
{
    "DEBUG",
    "INFO",
    "WARNING",
    "ERROR",
    0
};

static Log* logInstance = 0;
static bool threadErrorDisplayed = false;

Log::Log(Context* context) :
    Object(context),
#ifdef _DEBUG
    level_(LOG_DEBUG),
#else
    level_(LOG_INFO),
#endif
    timeStamp_(true),
    inWrite_(false),
    quiet_(false)
{
    logInstance = this;

    SubscribeToEvent(E_ENDFRAME, HANDLER(Log, HandleEndFrame));
}

Log::~Log()
{
    logInstance = 0;
}

void Log::Open(const String& fileName)
{
    #if !defined(ANDROID) && !defined(IOS)
    if (fileName.Empty())
        return;
    if (logFile_ && logFile_->IsOpen())
    {
        if (logFile_->GetName() == fileName)
            return;
        else
            Close();
    }

    logFile_ = new File(context_);
    if (logFile_->Open(fileName, FILE_WRITE))
        Write(LOG_INFO, "Opened log file " + fileName);
    else
    {
        logFile_.Reset();
        Write(LOG_ERROR, "Failed to create log file " + fileName);
    }
    #endif
}

void Log::Close()
{
    #if !defined(ANDROID) && !defined(IOS)
    if (logFile_ && logFile_->IsOpen())
    {
        logFile_->Close();
        logFile_.Reset();
    }
    #endif
}

void Log::SetLevel(int level)
{
    assert(level >= LOG_DEBUG && level < LOG_NONE);

    level_ = level;
}

void Log::SetTimeStamp(bool enable)
{
    timeStamp_ = enable;
}

void Log::SetQuiet(bool quiet)
{
    quiet_ = quiet;
}

void Log::Write(int level, const String& message)
{
    assert(level >= LOG_DEBUG && level < LOG_NONE);

    // If not in the main thread, store message for later processing
    if (!Thread::IsMainThread())
    {
        if (logInstance)
        {
            MutexLock lock(logInstance->logMutex_);
            logInstance->threadMessages_.Push(StoredLogMessage(message, level, false));
        }

        return;
    }

    // Do not log if message level excluded or if currently sending a log event
    if (!logInstance || logInstance->level_ > level || logInstance->inWrite_)
        return;

    String formattedMessage = logLevelPrefixes[level];
    formattedMessage += ": " + message;
    logInstance->lastMessage_ = message;

    if (logInstance->timeStamp_)
        formattedMessage = "[" + Time::GetTimeStamp() + "] " + formattedMessage;

    #if defined(ANDROID)
    int androidLevel = ANDROID_LOG_DEBUG + level;
    __android_log_print(androidLevel, "Urho3D", "%s", message.CString());
    #elif defined(IOS)
    SDL_IOS_LogMessage(message.CString());
    #else
    if (logInstance->quiet_)
    {
        // If in quiet mode, still print the error message to the standard error stream
        if (level == LOG_ERROR)
            PrintUnicodeLine(formattedMessage, true);
    }
    else
        PrintUnicodeLine(formattedMessage, level == LOG_ERROR);
    #endif

    if (logInstance->logFile_)
    {
        logInstance->logFile_->WriteLine(formattedMessage);
        logInstance->logFile_->Flush();
    }

    logInstance->inWrite_ = true;

    using namespace LogMessage;

    VariantMap& eventData = logInstance->GetEventDataMap();
    eventData[P_MESSAGE] = formattedMessage;
    eventData[P_LEVEL] = level;
    logInstance->SendEvent(E_LOGMESSAGE, eventData);

    logInstance->inWrite_ = false;
}

void Log::WriteRaw(const String& message, bool error)
{
    // If not in the main thread, store message for later processing
    if (!Thread::IsMainThread())
    {
        if (logInstance)
        {
            MutexLock lock(logInstance->logMutex_);
            logInstance->threadMessages_.Push(StoredLogMessage(message, LOG_RAW, error));
        }

        return;
    }

    // Prevent recursion during log event
    if (!logInstance || logInstance->inWrite_)
        return;

    logInstance->lastMessage_ = message;

    #if defined(ANDROID)
    if (logInstance->quiet_)
    {
        if (error)
            __android_log_print(ANDROID_LOG_ERROR, "Urho3D", message.CString());
    }
    else
        __android_log_print(error ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "Urho3D", message.CString());
    #elif defined(IOS)
    SDL_IOS_LogMessage(message.CString());
    #else
    if (logInstance->quiet_)
    {
        // If in quiet mode, still print the error message to the standard error stream
        if (error)
            PrintUnicode(message, true);
    }
    else
        PrintUnicode(message, error);
    #endif

    if (logInstance->logFile_)
    {
        logInstance->logFile_->Write(message.CString(), message.Length());
        logInstance->logFile_->Flush();
    }

    logInstance->inWrite_ = true;

    using namespace LogMessage;

    VariantMap& eventData = logInstance->GetEventDataMap();
    eventData[P_MESSAGE] = message;
    eventData[P_LEVEL] = error ? LOG_ERROR : LOG_INFO;
    logInstance->SendEvent(E_LOGMESSAGE, eventData);

    logInstance->inWrite_ = false;
}

void Log::HandleEndFrame(StringHash eventType, VariantMap& eventData)
{
    // If the MainThreadID is not valid, processing this loop can potentially be endless
    if (!Thread::IsMainThread())
    {
        if (!threadErrorDisplayed)
        {
            fprintf(stderr, "Thread::mainThreadID is not setup correctly! Threaded log handling disabled\n");
            threadErrorDisplayed = true;
        }
        return;
    }

    MutexLock lock(logMutex_);

    // Process messages accumulated from other threads (if any)
    while (!threadMessages_.Empty())
    {
        const StoredLogMessage& stored = threadMessages_.Front();

        if (stored.level_ != LOG_RAW)
            Write(stored.level_, stored.message_);
        else
            WriteRaw(stored.message_, stored.error_);

        threadMessages_.PopFront();
    }
}

}
<|endoftext|>