<commit_before>
#include "boxed.h"
#include "debug.h"
#include "function.h"
#include "value.h"
#include "gobject.h"
#include "gi.h"

#include <girffi.h>

using namespace v8;
using Nan::New;
using Nan::WeakCallbackType;

namespace GNodeJS {

static void FillArgument(GIArgInfo *arg_info,
                         GIArgument *argument,
                         Local<Value> value) {
    bool may_be_null = g_arg_info_may_be_null (arg_info);
    GITypeInfo type_info;
    g_arg_info_load_type (arg_info, &type_info);
    V8ToGIArgument(&type_info, argument, value, may_be_null);
}

static void AllocateArgument (GIBaseInfo *arg_info, GIArgument *argument) {
    gsize size;
    GITypeInfo arg_type;
    g_arg_info_load_type(arg_info, &arg_type);

    GITypeTag a_tag = g_type_info_get_tag(&arg_type);
    if (a_tag == GI_TYPE_TAG_INTERFACE) {
        GIInfoType i_type;
        GIBaseInfo *i_info;
        i_info = g_type_info_get_interface(&arg_type);
        i_type = g_base_info_get_type(i_info);

        if (i_type == GI_INFO_TYPE_STRUCT) {
            size = g_struct_info_get_size((GIStructInfo*)i_info);
        } else if (i_type == GI_INFO_TYPE_UNION) {
            size = g_union_info_get_size((GIUnionInfo*)i_info);
        } else if (i_type == GI_INFO_TYPE_INTERFACE) {
            g_warning("Allocate: arg %s \t interface %s",
                    g_base_info_get_name(arg_info),
                    g_base_info_get_name(i_info));
            size = g_struct_info_get_size(
                    g_interface_info_get_iface_struct(i_info));
        } else {
            DEBUG("arg OUT && caller-allocates && not supported: %s",
                    g_type_tag_to_string(a_tag));
            g_assert_not_reached();
        }

        argument->v_pointer = g_slice_alloc0(size);

        g_base_info_unref(i_info);
    } else {
        DEBUG("arg OUT && NOT INTERFACE: %s", g_type_tag_to_string(a_tag));
        g_assert_not_reached();
    }
}

/* see: /home/romgrk/src/gjs/gi/function.cpp */
void FunctionInvoker(const Nan::FunctionCallbackInfo<Value> &args) {
    //Isolate   *isolate = args.GetIsolate();
    FunctionInfo *func = (FunctionInfo *) External::Cast (*args.Data ())->Value ();

    GIBaseInfo *info = func->info;
    GError *error = NULL;

    int n_callable_args = g_callable_info_get_n_args ((GICallableInfo *) info);
    int n_total_args = n_callable_args;
    int n_out_args = 0;
    int n_in_args = 0;

    Parameter call_parameters[n_callable_args];

    for (int i = 0; i < n_callable_args; i++) {
        GIArgInfo arg_info;
        GITypeInfo type_info;
        g_callable_info_load_arg ((GICallableInfo *) info, i, &arg_info);
        g_arg_info_load_type (&arg_info, &type_info);

        int array_length_idx = g_type_info_get_array_length (&type_info);
        if (array_length_idx >= 0) {
            call_parameters[i].type = Parameter::ARRAY;
            call_parameters[array_length_idx].type = Parameter::SKIP;
        }

        if (call_parameters[i].type == Parameter::SKIP)
            continue;

        if (g_arg_info_get_direction (&arg_info) == GI_DIRECTION_IN ||
            g_arg_info_get_direction (&arg_info) == GI_DIRECTION_INOUT)
            n_in_args++;
    }

    if (args.Length() < n_in_args) {
        Nan::ThrowTypeError(g_strdup_printf(
            "Not enough arguments; expected %i, have %i",
                n_in_args, args.Length()));
        return;
    }

    GIFunctionInfoFlags flags = g_function_info_get_flags (info);
    gboolean is_method = ((flags & GI_FUNCTION_IS_METHOD) != 0 &&
                          (flags & GI_FUNCTION_IS_CONSTRUCTOR) == 0);
    if (is_method)
        n_total_args++;

    gboolean can_throw = g_callable_info_can_throw_gerror (info);
    if (can_throw)
        n_total_args++;

    GIArgument total_arg_values[n_total_args];
    GIArgument *callable_arg_values;

    if (is_method) {
        GIBaseInfo *container = g_base_info_get_container (func->info);
        V8ToGIArgument(container, &total_arg_values[0], args.This() );
        callable_arg_values = &total_arg_values[1];
    } else {
        callable_arg_values = &total_arg_values[0];
    }

    int in_arg = 0, i = 0;
    for (; i < n_callable_args; i++) {
        if (call_parameters[i].type == Parameter::SKIP)
            continue;

        GIArgInfo arg_info = {};
        g_callable_info_load_arg ((GICallableInfo *) info, i, &arg_info);
        GIDirection direction = g_arg_info_get_direction (&arg_info);

        if (direction == GI_DIRECTION_OUT) {
            n_out_args++;

            if (g_arg_info_is_caller_allocates (&arg_info)) {
                AllocateArgument(&arg_info, &callable_arg_values[i]);
            } else /* is_callee_allocates */ {
                callable_arg_values[i].v_pointer = NULL;
            }
        }
        if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
            /* Fill the in-argument if it is null and nullable */
            FillArgument(&arg_info, &callable_arg_values[i], args[in_arg]);

            if (call_parameters[i].type == Parameter::ARRAY) {
                GITypeInfo type_info;
                g_arg_info_load_type (&arg_info, &type_info);

                int array_length_pos = g_type_info_get_array_length (&type_info);
                GIArgInfo array_length_arg;
                g_callable_info_load_arg(info, array_length_pos, &array_length_arg);

                int array_length;
                //array_length = GetArrayLength (args[in_arg]);
                if (args[in_arg]->IsArray())
                    array_length = Local<Array>::Cast (args[in_arg]->ToObject ())->Length();
                else if (args[in_arg]->IsString())
                    array_length = Local<String>::Cast (args[in_arg]->ToObject ())->Length();
                else if (args[in_arg]->IsNull())
                    array_length = 0;
                else
                    g_assert_not_reached();

                Local<Value> array_length_value = New(array_length);
                FillArgument(
                        &array_length_arg,
                        &callable_arg_values[array_length_pos],
                        array_length_value);
            }
            in_arg++;
        }
        if (direction == GI_DIRECTION_INOUT) {
            WARN("FunctionInvoker: arg INOUT: %s ", g_base_info_get_name(&arg_info));
            WARN("Value: %s", *String::Utf8Value(args[in_arg]->ToString()) );
        }
    }

    if (can_throw)
        callable_arg_values[i].v_pointer = &error;

    void *ffi_arg_pointers[n_total_args];
    for (int i = 0; i < n_total_args; i++)
        ffi_arg_pointers[i] = &total_arg_values[i];

    GIArgument return_value;
    ffi_call (&func->invoker.cif, FFI_FN (func->invoker.native_address),
              &return_value, ffi_arg_pointers);

    GITypeInfo return_type;
    g_callable_info_load_return_type(info, &return_type);
    GITypeTag  return_tag      = g_type_info_get_tag(&return_type);
    GITransfer return_transfer = g_callable_info_get_caller_owns(info);

    //bool retValueLoaded = false;
    //FreeGIArgument(&return_type, &return_value);
    gboolean skip_return = g_callable_info_skip_return(info);
    //gboolean may_return_null = g_callable_info_may_return_null(info);
    if (return_transfer == GI_TRANSFER_NOTHING) {
        //if (skip_return == FALSE)
            //g_warning("Return: (transfer none) (no-skip!) %s ",
                //(may_return_null ? "(allow-none)" : ""));
    } else if (return_transfer == GI_TRANSFER_CONTAINER) {
        //g_warning("Return: (transfer container) %s ",
                //(may_return_null ? "(allow-none)" : ""));
    } else if (return_transfer == GI_TRANSFER_EVERYTHING) {
        //g_warning("Return: (transfer full) %s ",
            //(may_return_null ? "(allow-none)" : ""));
        //if (!may_return_null)
    }

    if (return_tag != GI_TYPE_TAG_VOID && (skip_return == FALSE))
        n_out_args++;

    for (int i = 0; i < n_callable_args; i++) {
        GIArgInfo  arg_info = {};
        GITypeInfo arg_type;
        GIDirection direction;
        g_callable_info_load_arg ((GICallableInfo *) info, i, &arg_info);
        g_arg_info_load_type (&arg_info, &arg_type);
        direction = g_arg_info_get_direction (&arg_info);

        if (direction == GI_DIRECTION_OUT) { //|| direction == GI_DIRECTION_INOUT)
            args.GetReturnValue().Set(
                    GIArgumentToV8(&arg_type, &callable_arg_values[i]) );
            //retValueLoaded = true;
        } else if (direction == GI_DIRECTION_INOUT) {
            // XXX is there something to do here?
            g_warning("INOUT: %s", g_base_info_get_name(&arg_info));
        } else {
            FreeGIArgument (&arg_type, &callable_arg_values[i]);
        }
    }

    if (error) {
        Nan::ThrowError(error->message);
        g_error_free(error);
        return;
    }

    if (return_tag != GI_TYPE_TAG_VOID)
        args.GetReturnValue().Set(
                GIArgumentToV8(&return_type, &return_value));

    //if (return_transfer == GI_TRANSFER_CONTAINER)
        //FreeGIArgument(&return_type, &return_value);
}

void FunctionDestroyed(const v8::WeakCallbackInfo<FunctionInfo> &data) {
    FunctionInfo *func = data.GetParameter ();
    g_base_info_unref (func->info);
    g_function_invoker_destroy (&func->invoker);
    g_free (func);
}

NAN_METHOD(FunctionInfoToString) {
    //Isolate *isolate = info.GetIsolate();
    FunctionInfo *func = (FunctionInfo *) External::Cast(*info.Holder());
    GIFunctionInfo *fn = func->info;
    GString *args_string = g_string_new("");

    int n_args = g_callable_info_get_n_args(fn);
    for (int i = 0; i < n_args; i++) {
        if (i != 0)
            g_string_append(args_string, ", ");
        GIArgInfo *arg_info = nullptr;
        arg_info = g_callable_info_get_arg(fn, i);
        g_string_append(args_string, g_base_info_get_name(arg_info));
        g_base_info_unref(arg_info);
    }

    gchar *args = g_string_free(args_string, FALSE);
    gchar *string = g_strdup_printf("function %s (%s) {}",
            g_function_info_get_symbol(fn),
            args);
    Local<String> result = UTF8(string);

    g_free(args);
    g_free(string);
    info.GetReturnValue().Set(result);
}

Local<Function> MakeFunction(GIBaseInfo *info) {
    FunctionInfo *func = g_new0 (FunctionInfo, 1);
    func->info = g_base_info_ref (info);
    g_function_info_prep_invoker (func->info, &func->invoker, NULL);
    auto tpl = New<FunctionTemplate>(FunctionInvoker, New<External>(func));

    Local<Function> fn = tpl->GetFunction();
    fn->SetName(
        New(g_function_info_get_symbol(info)).ToLocalChecked());

    Isolate *isolate = Isolate::GetCurrent();
    v8::Persistent<v8::FunctionTemplate> persistent(isolate, tpl);
    persistent.SetWeak(func, FunctionDestroyed, WeakCallbackType::kParameter);

    return fn;
}

#if 0
class TrampolineInfo {
    ffi_cif cif;
    ffi_closure *closure;
    Persistent<Function> persistent;
    GICallableInfo *info;
    GIScopeType scope_type;

    TrampolineInfo(Handle<Function>  function,
                   GICallableInfo   *info,
                   GIScopeType       scope_type);

    void Dispose();
    static void Call(ffi_cif *cif, void *result, void **args, void *data);
    void *GetClosure();
};

void TrampolineInfo::Dispose() {
    persistent = nullptr;
    g_base_info_unref (info);
    g_callable_info_free_closure (info, closure);
};

void TrampolineInfo::Call(ffi_cif *cif,
                          void *result,
                          void **args,
                          void *data) {
    TrampolineInfo *trampoline = (TrampolineInfo *) data;

    int argc = g_callable_info_get_n_args (trampoline->info);
    Handle<Value> argv[argc];

    for (int i = 0; i < argc; i++) {
        GIArgInfo arg_info;
        g_callable_info_load_arg (trampoline->info, i, &arg_info);
        GITypeInfo type_info;
        g_arg_info_load_type (&arg_info, &type_info);
        argv[i] = GIArgumentToV8 (&type_info, (GIArgument *) &args[i]);
    }

    Handle<Function> func = trampoline->func;
    /* Provide a bogus "this" function. Any interested callers should
     * bind their callbacks to what they're intersted in... */
    Handle<Object> this_obj = func;
    Handle<Value> return_value = func->Call (this_obj, argc, argv);
    GITypeInfo type_info;
    g_callable_info_load_return_type (trampoline->info, &type_info);
    V8ToGIArgument (&type_info, (GIArgument *) &result, return_value,
                    g_callable_info_may_return_null (trampoline->info));
}

TrampolineInfo::TrampolineInfo(Handle<Function>  function,
                               GICallableInfo   *info,
                               GIScopeType       scope_type) {
    this->closure = g_callable_info_prepare_closure (info, &cif, Call, this);
    this->func = Persistent<Function>::New (function);
    this->info = g_base_info_ref (info);
    this->scope_type = scope_type;
}
#endif

};
<commit_msg>remove argument allocation for GI_INFO_TYPE_INTERFACE<commit_after>
#include "boxed.h"
#include "debug.h"
#include "function.h"
#include "value.h"
#include "gobject.h"

#include <girffi.h>

using namespace v8;
using Nan::New;
using Nan::WeakCallbackType;

namespace GNodeJS {

static void FillArgument(GIArgInfo *arg_info,
                         GIArgument *argument,
                         Local<Value> value) {
    GITypeInfo type_info;
    bool may_be_null = g_arg_info_may_be_null (arg_info);
    g_arg_info_load_type (arg_info, &type_info);
    V8ToGIArgument(&type_info, argument, value, may_be_null);
}

static void AllocateArgument (GIBaseInfo *arg_info, GIArgument *argument) {
    gsize size;
    GITypeInfo arg_type;
    g_arg_info_load_type(arg_info, &arg_type);

    GITypeTag a_tag = g_type_info_get_tag(&arg_type);
    if (a_tag == GI_TYPE_TAG_INTERFACE) {
        GIInfoType i_type;
        GIBaseInfo *i_info;
        i_info = g_type_info_get_interface(&arg_type);
        i_type = g_base_info_get_type(i_info);

        if (i_type == GI_INFO_TYPE_STRUCT) {
            size = g_struct_info_get_size((GIStructInfo*)i_info);
        } else if (i_type == GI_INFO_TYPE_UNION) {
            size = g_union_info_get_size((GIUnionInfo*)i_info);
        } else {
            DEBUG("arg OUT && caller-allocates && not supported: %s",
                    g_type_tag_to_string(a_tag));
            g_assert_not_reached();
        }

        argument->v_pointer = g_slice_alloc0(size);

        g_base_info_unref(i_info);
    } else {
        DEBUG("arg OUT && NOT INTERFACE: %s", g_type_tag_to_string(a_tag));
        g_assert_not_reached();
    }
}

/* see: /home/romgrk/src/gjs/gi/function.cpp */
void FunctionInvoker(const Nan::FunctionCallbackInfo<Value> &args) {
    //Isolate   *isolate = args.GetIsolate();
    FunctionInfo *func = (FunctionInfo *) External::Cast (*args.Data ())->Value ();
    GIBaseInfo *info = func->info; // do-not-free

    int n_callable_args = g_callable_info_get_n_args ((GICallableInfo *) info);
    int n_total_args = n_callable_args;
    int n_out_args = 0;
    int n_in_args = 0;

    Parameter call_parameters[n_callable_args];

    for (int i = 0; i < n_callable_args; i++) {
        GIArgInfo arg_info;
        GITypeInfo type_info;
        g_callable_info_load_arg ((GICallableInfo *) info, i, &arg_info);
        g_arg_info_load_type (&arg_info, &type_info);

        int array_length_idx = g_type_info_get_array_length (&type_info);
        if (array_length_idx >= 0) {
            call_parameters[i].type = Parameter::ARRAY;
            call_parameters[array_length_idx].type = Parameter::SKIP;
        }

        if (call_parameters[i].type == Parameter::SKIP)
            continue;

        if (g_arg_info_get_direction (&arg_info) == GI_DIRECTION_IN ||
            g_arg_info_get_direction (&arg_info) == GI_DIRECTION_INOUT)
            n_in_args++;
    }

    if (args.Length() < n_in_args) {
        char *msg = g_strdup_printf(
            "Not enough arguments; expected %i, have %i",
            n_in_args, args.Length());
        Nan::ThrowTypeError(msg);
        g_free(msg);
        return;
    }

    GIFunctionInfoFlags flags = g_function_info_get_flags (info);
    gboolean is_method = ((flags & GI_FUNCTION_IS_METHOD) != 0 &&
                          (flags & GI_FUNCTION_IS_CONSTRUCTOR) == 0);
    gboolean can_throw = g_callable_info_can_throw_gerror (info);

    if (is_method)
        n_total_args++;

    if (can_throw)
        n_total_args++;

    GIArgument total_arg_values[n_total_args];
    GIArgument *callable_arg_values;
    GError *error = NULL;

    if (is_method) {
        GIBaseInfo *container = g_base_info_get_container (func->info);
        V8ToGIArgument(container, &total_arg_values[0], args.This() );
        callable_arg_values = &total_arg_values[1];
    } else {
        callable_arg_values = &total_arg_values[0];
    }

    int in_arg = 0,
        i = 0;
    for (; i < n_callable_args; i++) {
        if (call_parameters[i].type == Parameter::SKIP)
            continue;

        GIArgInfo arg_info = {};
        g_callable_info_load_arg ((GICallableInfo *) info, i, &arg_info);
        GIDirection direction = g_arg_info_get_direction (&arg_info);

        if (direction == GI_DIRECTION_OUT) {
            n_out_args++;

            if (g_arg_info_is_caller_allocates (&arg_info)) {
                AllocateArgument(&arg_info, &callable_arg_values[i]);
            } else /* is_callee_allocates */ {
                callable_arg_values[i].v_pointer = NULL;
            }
        }
        if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
            /* Fill the in-argument if it is null and nullable */
            FillArgument(&arg_info, &callable_arg_values[i], args[in_arg]);

            if (call_parameters[i].type == Parameter::ARRAY) {
                GITypeInfo type_info;
                GIArgInfo array_length_arg;
                g_arg_info_load_type (&arg_info, &type_info);
                int array_length_pos = g_type_info_get_array_length (&type_info);
                g_callable_info_load_arg(info, array_length_pos, &array_length_arg);

                int array_length;
                //array_length = GetArrayLength (args[in_arg]);
                if (args[in_arg]->IsArray())
                    array_length = Local<Array>::Cast (args[in_arg]->ToObject ())->Length();
                else if (args[in_arg]->IsString())
                    array_length = Local<String>::Cast (args[in_arg]->ToObject ())->Length();
                else if (args[in_arg]->IsNull())
                    array_length = 0;
                else
                    g_assert_not_reached();

                FillArgument(
                        &array_length_arg,
                        &callable_arg_values[array_length_pos],
                        New(array_length));
            }
            in_arg++;
        }
        if (direction == GI_DIRECTION_INOUT) {
            WARN("FunctionInvoker: arg INOUT: %s ", g_base_info_get_name(&arg_info));
            WARN("Value: %s", *String::Utf8Value(args[in_arg]->ToString()) );
        }
    }

    if (can_throw)
        callable_arg_values[i].v_pointer = &error;

    void *ffi_arg_pointers[n_total_args];
    for (int i = 0; i < n_total_args; i++)
        ffi_arg_pointers[i] = &total_arg_values[i];

    GIArgument return_value;
    ffi_call (&func->invoker.cif, FFI_FN (func->invoker.native_address),
              &return_value, ffi_arg_pointers);

    GITypeInfo return_type;
    g_callable_info_load_return_type(info, &return_type);
    GITypeTag  return_tag      = g_type_info_get_tag(&return_type);
    GITransfer return_transfer = g_callable_info_get_caller_owns(info);

    //FreeGIArgument(&return_type, &return_value);
    gboolean skip_return = g_callable_info_skip_return(info);
    // gboolean may_return_null = g_callable_info_may_return_null(info);

    if (return_tag != GI_TYPE_TAG_VOID && (skip_return == FALSE))
        n_out_args++;

    if (return_transfer == GI_TRANSFER_NOTHING) {
        //if (skip_return == FALSE)
            //g_warning("Return: (transfer none) (no-skip!) %s ",
                //(may_return_null ? "(allow-none)" : ""));
    } else if (return_transfer == GI_TRANSFER_CONTAINER) {
        //g_warning("Return: (transfer container) %s ",
                //(may_return_null ? "(allow-none)" : ""));
    } else if (return_transfer == GI_TRANSFER_EVERYTHING) {
        // WARN("Return: (transfer full) %s ", g_type_tag_to_string(return_tag));
        // g_warning(g_base_info_get_name(&return_type));
        //if (!may_return_null)(may_return_null ? "(allow-none)" : ""),
    }

    if (n_out_args > 1)
        WARN("FunctionInvoker: n_out_args == %i", n_out_args);

    for (int i = 0; i < n_callable_args; i++) {
        GIArgInfo  arg_info = {};
        GITypeInfo arg_type;
        GIDirection direction;
        g_callable_info_load_arg ((GICallableInfo *) info, i, &arg_info);
        g_arg_info_load_type (&arg_info, &arg_type);
        direction = g_arg_info_get_direction (&arg_info);

        if (direction == GI_DIRECTION_OUT) { //|| direction == GI_DIRECTION_INOUT)
            args.GetReturnValue().Set(
                    GIArgumentToV8(&arg_type, &callable_arg_values[i]) );
        } else if (direction == GI_DIRECTION_INOUT) {
            // XXX is there something to do here?
            g_warning("INOUT: %s", g_base_info_get_name(&arg_info));
        } else {
            FreeGIArgument (&arg_type, &callable_arg_values[i]);
        }
    }

    if (error) {
        Nan::ThrowError(error->message);
        g_error_free(error);
        return;
    }

    // FIXME handle more than 1 return value
    if (return_tag != GI_TYPE_TAG_VOID) {
        args.GetReturnValue().Set(
                GIArgumentToV8(&return_type, &return_value));
        //if (return_transfer == GI_TRANSFER_CONTAINER)
        FreeGIArgument(&return_type, &return_value);
    }
}

void FunctionDestroyed(const v8::WeakCallbackInfo<FunctionInfo> &data) {
    FunctionInfo *func = data.GetParameter ();

    WARN("FunctionDestroyed: %s", g_base_info_get_name(func->info));

    g_base_info_unref (func->info);
    g_function_invoker_destroy (&func->invoker);
    g_free (func);
}

NAN_METHOD(FunctionInfoToString) {
    //Isolate *isolate = info.GetIsolate();
    FunctionInfo *func = (FunctionInfo *) External::Cast (*info.Data ())->Value ();
    GIBaseInfo *fn = func->info; // do-not-free
    GString *args_string = g_string_new("");

    int n_args = g_callable_info_get_n_args(fn);
    for (int i = 0; i < n_args; i++) {
        if (i != 0)
            g_string_append(args_string, ", ");
        GIArgInfo *arg_info = nullptr;
        arg_info = g_callable_info_get_arg(fn, i);
        g_string_append(args_string, g_base_info_get_name(arg_info));
        g_base_info_unref(arg_info);
    }

    gchar *args = g_string_free(args_string, FALSE);
    gchar *string = g_strdup_printf("function %s (%s) { [GObject code] }",
            g_function_info_get_symbol(fn),
            args);
    Local<String> result = UTF8(string);

    g_free(args);
    g_free(string);
    info.GetReturnValue().Set(result);
}

Local<Function> MakeFunction(GIBaseInfo *info) {
    FunctionInfo *func = g_new0 (FunctionInfo, 1);
    func->info = g_base_info_ref (info);
    g_function_info_prep_invoker (func->info, &func->invoker, NULL);

    auto external = New<External>(func);

    int n_args = g_callable_info_get_n_args(info);
    Local<String> name = New(g_function_info_get_symbol(info)).ToLocalChecked();
    Local<Function> toString = New<FunctionTemplate>(FunctionInfoToString, external)->GetFunction();

    auto tpl = New<FunctionTemplate>(FunctionInvoker, external);
    tpl->SetLength(n_args);

    auto fn = tpl->GetFunction();
    fn->SetName(name);
    fn->Set(UTF8("toString"), toString);

    Isolate *isolate = Isolate::GetCurrent();
    Persistent<FunctionTemplate> persistent(isolate, tpl);
    persistent.SetWeak(func, FunctionDestroyed, WeakCallbackType::kParameter);

    return fn;
}

#if 0
class TrampolineInfo {
    ffi_cif cif;
    ffi_closure *closure;
    Persistent<Function> persistent;
    GICallableInfo *info;
    GIScopeType scope_type;

    TrampolineInfo(Handle<Function>  function,
                   GICallableInfo   *info,
                   GIScopeType       scope_type);

    void Dispose();
    static void Call(ffi_cif *cif, void *result, void **args, void *data);
    void *GetClosure();
};

void TrampolineInfo::Dispose() {
    persistent = nullptr;
    g_base_info_unref (info);
    g_callable_info_free_closure (info, closure);
};

void TrampolineInfo::Call(ffi_cif *cif,
                          void *result,
                          void **args,
                          void *data) {
    TrampolineInfo *trampoline = (TrampolineInfo *) data;

    int argc = g_callable_info_get_n_args (trampoline->info);
    Handle<Value> argv[argc];

    for (int i = 0; i < argc; i++) {
        GIArgInfo arg_info;
        g_callable_info_load_arg (trampoline->info, i, &arg_info);
        GITypeInfo type_info;
        g_arg_info_load_type (&arg_info, &type_info);
        argv[i] = GIArgumentToV8 (&type_info, (GIArgument *) &args[i]);
    }

    Handle<Function> func = trampoline->func;
    /* Provide a bogus "this" function. Any interested callers should
     * bind their callbacks to what they're intersted in... */
    Handle<Object> this_obj = func;
    Handle<Value> return_value = func->Call (this_obj, argc, argv);
    GITypeInfo type_info;
    g_callable_info_load_return_type (trampoline->info, &type_info);
    V8ToGIArgument (&type_info, (GIArgument *) &result, return_value,
                    g_callable_info_may_return_null (trampoline->info));
}

TrampolineInfo::TrampolineInfo(Handle<Function>  function,
                               GICallableInfo   *info,
                               GIScopeType       scope_type) {
    this->closure = g_callable_info_prepare_closure (info, &cif, Call, this);
    this->func = Persistent<Function>::New (function);
    this->info = g_base_info_ref (info);
    this->scope_type = scope_type;
}
#endif

};
<|endoftext|>


<commit_before>#pragma once

#include "../std/shared_ptr.hpp"
#include "../std/map.hpp"
#include "../std/string.hpp"
#include "../std/list.hpp"
#include "../std/vector.hpp"

#include "../base/mutex.hpp"
#include "../base/resource_pool.hpp"

#include "opengl/storage.hpp"
#include "opengl/program_manager.hpp"
#include "glyph_cache.hpp"
#include "data_formats.hpp"
#include "defines.hpp"

namespace graphics
{
  class ResourceCache;

  namespace gl
  {
    class BaseTexture;
    class Storage;
    class ProgramManager;
  }

  struct GlyphInfo;

  struct TTextureFactory : BasePoolElemFactory
  {
    size_t m_w;
    size_t m_h;
    graphics::DataFormat m_format;
    TTextureFactory(size_t w,
                    size_t h,
                    graphics::DataFormat format,
                    char const * resName,
                    size_t batchSize);
    shared_ptr<gl::BaseTexture> const Create();
  };

  struct TStorageFactory : BasePoolElemFactory
  {
    size_t m_vbSize;
    size_t m_ibSize;
    bool m_useSingleThreadedOGL;
    TStorageFactory(size_t vbSize,
                    size_t ibSize,
                    bool useSingleThreadedOGL,
                    char const * resName,
                    size_t batchSize);
    gl::Storage const Create();
    void BeforeMerge(gl::Storage const & e);
  };

  /// ---- Texture Pools ----

  /// Basic texture pool traits
  typedef BasePoolTraits<shared_ptr<gl::BaseTexture>, TTextureFactory> TBaseTexturePoolTraits;

  /// Fixed-Size texture pool
  typedef FixedSizePoolTraits<TTextureFactory, TBaseTexturePoolTraits > TFixedSizeTexturePoolTraits;
  typedef ResourcePoolImpl<TFixedSizeTexturePoolTraits> TFixedSizeTexturePoolImpl;

  /// On-Demand multi-threaded texture pool

  typedef AllocateOnDemandMultiThreadedPoolTraits<TTextureFactory, TBaseTexturePoolTraits> TOnDemandMultiThreadedTexturePoolTraits;
  typedef ResourcePoolImpl<TOnDemandMultiThreadedTexturePoolTraits> TOnDemandMultiThreadedTexturePoolImpl;

  /// On-Demand single-threaded texture pool
  /// (with postponed resource allocation)
  typedef AllocateOnDemandSingleThreadedPoolTraits<TTextureFactory, TBaseTexturePoolTraits> TOnDemandSingleThreadedTexturePoolTraits;
  typedef ResourcePoolImpl<TOnDemandSingleThreadedTexturePoolTraits> TOnDemandSingleThreadedTexturePoolImpl;

  /// Interface for texture pool
  typedef ResourcePool<shared_ptr<gl::BaseTexture> > TTexturePool;

  /// ---- Storage Pools ----

  /// Basic storage traits
  typedef BasePoolTraits<gl::Storage, TStorageFactory> TBaseStoragePoolTraits;

  /// Fixed-Size mergeable storage pool
  typedef SeparateFreePoolTraits<TStorageFactory, TBaseStoragePoolTraits> TSeparateFreeStoragePoolTraits;
  typedef FixedSizePoolTraits<TStorageFactory, TSeparateFreeStoragePoolTraits> TFixedSizeMergeableStoragePoolTraits;
  typedef ResourcePoolImpl<TFixedSizeMergeableStoragePoolTraits> TFixedSizeMergeableStoragePoolImpl;

  /// Fixed-Size non-mergeable storage pool
  typedef FixedSizePoolTraits<TStorageFactory, TBaseStoragePoolTraits> TFixedSizeNonMergeableStoragePoolTraits;
  typedef ResourcePoolImpl<TFixedSizeNonMergeableStoragePoolTraits> TFixedSizeNonMergeableStoragePoolImpl;

  /// On-Demand single-threaded storage pool
  /// (with postponed resource allocation and separate list of freed resources)
  typedef AllocateOnDemandSingleThreadedPoolTraits<TStorageFactory, TSeparateFreeStoragePoolTraits> TOnDemandSingleThreadedStoragePoolTraits;
  typedef ResourcePoolImpl<TOnDemandSingleThreadedStoragePoolTraits> TOnDemandSingleThreadedStoragePoolImpl;

  /// On-Demand multi-threaded storage pool
  typedef AllocateOnDemandMultiThreadedPoolTraits<TStorageFactory, TBaseStoragePoolTraits> TOnDemandMultiThreadedStoragePoolTraits;
  typedef ResourcePoolImpl<TOnDemandMultiThreadedStoragePoolTraits> TOnDemandMultiThreadedStoragePoolImpl;

  /// Interface for storage pool
  typedef ResourcePool<gl::Storage> TStoragePool;

  class ResourceManager
  {
  public:

    struct StoragePoolParams
    {
      size_t m_vbSize;
      size_t m_vertexSize;
      size_t m_ibSize;
      size_t m_indexSize;
      size_t m_storagesCount;
      EStorageType m_storageType;
      bool m_isDebugging;

      StoragePoolParams();
      StoragePoolParams(EStorageType storageType);
      StoragePoolParams(size_t vbSize,
                        size_t vertexSize,
                        size_t ibSize,
                        size_t indexSize,
                        size_t storagesCount,
                        EStorageType storageType,
                        bool isDebugging);

      bool isValid() const;
    };

    struct TexturePoolParams
    {
      size_t m_texWidth;
      size_t m_texHeight;
      size_t m_texCount;
      graphics::DataFormat m_format;
      ETextureType m_textureType;
      bool m_isDebugging;

      TexturePoolParams();
      TexturePoolParams(ETextureType textureType);
      TexturePoolParams(size_t texWidth,
                        size_t texHeight,
                        size_t texCount,
                        graphics::DataFormat format,
                        ETextureType textureType,
                        bool isDebugging);

      bool isValid() const;
    };

    struct GlyphCacheParams
    {
      string m_unicodeBlockFile;
      string m_whiteListFile;
      string m_blackListFile;

      size_t m_glyphCacheMemoryLimit;

      GlyphCacheParams();
      GlyphCacheParams(string const & unicodeBlockFile,
                       string const & whiteListFile,
                       string const & blackListFile,
                       size_t glyphCacheMemoryLimit);
    };

    struct Params
    {
    private:

      string m_vendorName;
      string m_rendererName;

      /// check non-strict matching upon vendorName and rendererName
      bool isGPU(char const * vendorName, char const * rendererName, bool strictMatch) const;

    public:

      DataFormat m_rtFormat;
      DataFormat m_texFormat;
      DataFormat m_texRtFormat;
      bool m_useSingleThreadedOGL;
      bool m_useReadPixelsToSynchronize;

      size_t m_videoMemoryLimit;

      /// storages params
      vector<StoragePoolParams> m_storageParams;

      /// textures params
      vector<TexturePoolParams> m_textureParams;

      /// glyph caches params
      GlyphCacheParams m_glyphCacheParams;

      unsigned m_renderThreadsCount;
      unsigned m_threadSlotsCount;

      Params();

      void distributeFreeMemory(int freeVideoMemory);
      void checkDeviceCaps();
      int memoryUsage() const;
      int fixedMemoryUsage() const;
      void initScaleWeights();
    };

  private:

    typedef map<string, shared_ptr<gl::BaseTexture> > TStaticTextures;

    TStaticTextures m_staticTextures;

    threads::Mutex m_mutex;

    vector<shared_ptr<TTexturePool> > m_texturePools;
    vector<shared_ptr<TStoragePool> > m_storagePools;

    struct ThreadSlot
    {
      shared_ptr<gl::ProgramManager> m_programManager;
      shared_ptr<GlyphCache> m_glyphCache;
    };

    vector<ThreadSlot> m_threadSlots;

    Params m_params;

  public:

    ResourceManager(Params const & p);

    void initThreadSlots(Params const & p);

    void initStoragePool(StoragePoolParams const & p, shared_ptr<TStoragePool> & pool);

    TStoragePool * storagePool(EStorageType type);

    void initTexturePool(TexturePoolParams const & p, shared_ptr<TTexturePool> & pool);

    TTexturePool * texturePool(ETextureType type);

    shared_ptr<gl::BaseTexture> const & getTexture(string const & fileName);

    Params const & params() const;

    shared_ptr<GlyphInfo> const getGlyphInfo(GlyphKey const & key);
    GlyphMetrics const getGlyphMetrics(GlyphKey const & key);
    GlyphCache * glyphCache(int threadSlot = 0);

    int renderThreadSlot(int threadNum) const;
    int guiThreadSlot() const;
    int cacheThreadSlot() const;

    void addFonts(vector<string> const & fontNames);

    void memoryWarning();
    void enterBackground();
    void enterForeground();

    void updatePoolState();

    void cancel();

    bool useReadPixelsToSynchronize() const;

    shared_ptr<graphics::gl::BaseTexture> createRenderTarget(unsigned w, unsigned h);
    gl::ProgramManager * programManager(int threadSlot);
  };

  void loadSkin(shared_ptr<ResourceManager> const & rm,
                string const & fileName,
                vector<shared_ptr<ResourceCache> > & caches);
}

<commit_msg>removed "dead code"<commit_after>#pragma once

#include "../std/shared_ptr.hpp"
#include "../std/map.hpp"
#include "../std/string.hpp"
#include "../std/list.hpp"
#include "../std/vector.hpp"

#include "../base/mutex.hpp"
#include "../base/resource_pool.hpp"

#include "opengl/storage.hpp"
#include "opengl/program_manager.hpp"
#include "glyph_cache.hpp"
#include "data_formats.hpp"
#include "defines.hpp"

namespace graphics
{
  class ResourceCache;

  namespace gl
  {
    class BaseTexture;
    class Storage;
    class ProgramManager;
  }

  struct GlyphInfo;

  struct TTextureFactory : BasePoolElemFactory
  {
    size_t m_w;
    size_t m_h;
    graphics::DataFormat m_format;
    TTextureFactory(size_t w,
                    size_t h,
                    graphics::DataFormat format,
                    char const * resName,
                    size_t batchSize);
    shared_ptr<gl::BaseTexture> const Create();
  };

  struct TStorageFactory : BasePoolElemFactory
  {
    size_t m_vbSize;
    size_t m_ibSize;
    bool m_useSingleThreadedOGL;
    TStorageFactory(size_t vbSize,
                    size_t ibSize,
                    bool useSingleThreadedOGL,
                    char const * resName,
                    size_t batchSize);
    gl::Storage const Create();
    void BeforeMerge(gl::Storage const & e);
  };

  /// ---- Texture Pools ----

  /// Basic texture pool traits
  typedef BasePoolTraits<shared_ptr<gl::BaseTexture>, TTextureFactory> TBaseTexturePoolTraits;

  /// Fixed-Size texture pool
  typedef FixedSizePoolTraits<TTextureFactory, TBaseTexturePoolTraits > TFixedSizeTexturePoolTraits;
  typedef ResourcePoolImpl<TFixedSizeTexturePoolTraits> TFixedSizeTexturePoolImpl;

  /// On-Demand multi-threaded texture pool

  typedef AllocateOnDemandMultiThreadedPoolTraits<TTextureFactory, TBaseTexturePoolTraits> TOnDemandMultiThreadedTexturePoolTraits;
  typedef ResourcePoolImpl<TOnDemandMultiThreadedTexturePoolTraits> TOnDemandMultiThreadedTexturePoolImpl;

  /// On-Demand single-threaded texture pool
  /// (with postponed resource allocation)
  typedef AllocateOnDemandSingleThreadedPoolTraits<TTextureFactory, TBaseTexturePoolTraits> TOnDemandSingleThreadedTexturePoolTraits;
  typedef ResourcePoolImpl<TOnDemandSingleThreadedTexturePoolTraits> TOnDemandSingleThreadedTexturePoolImpl;

  /// Interface for texture pool
  typedef ResourcePool<shared_ptr<gl::BaseTexture> > TTexturePool;

  /// ---- Storage Pools ----

  /// Basic storage traits
  typedef BasePoolTraits<gl::Storage, TStorageFactory> TBaseStoragePoolTraits;

  /// Fixed-Size mergeable storage pool
  typedef SeparateFreePoolTraits<TStorageFactory, TBaseStoragePoolTraits> TSeparateFreeStoragePoolTraits;
  typedef FixedSizePoolTraits<TStorageFactory, TSeparateFreeStoragePoolTraits> TFixedSizeMergeableStoragePoolTraits;
  typedef ResourcePoolImpl<TFixedSizeMergeableStoragePoolTraits> TFixedSizeMergeableStoragePoolImpl;

  /// Fixed-Size non-mergeable storage pool
  typedef FixedSizePoolTraits<TStorageFactory, TBaseStoragePoolTraits> TFixedSizeNonMergeableStoragePoolTraits;
  typedef ResourcePoolImpl<TFixedSizeNonMergeableStoragePoolTraits> TFixedSizeNonMergeableStoragePoolImpl;

  /// On-Demand single-threaded storage pool
  /// (with postponed resource allocation and separate list of freed resources)
  typedef AllocateOnDemandSingleThreadedPoolTraits<TStorageFactory, TSeparateFreeStoragePoolTraits> TOnDemandSingleThreadedStoragePoolTraits;
  typedef ResourcePoolImpl<TOnDemandSingleThreadedStoragePoolTraits> TOnDemandSingleThreadedStoragePoolImpl;

  /// On-Demand multi-threaded storage pool
  typedef AllocateOnDemandMultiThreadedPoolTraits<TStorageFactory, TBaseStoragePoolTraits> TOnDemandMultiThreadedStoragePoolTraits;
  typedef ResourcePoolImpl<TOnDemandMultiThreadedStoragePoolTraits> TOnDemandMultiThreadedStoragePoolImpl;

  /// Interface for storage pool
  typedef ResourcePool<gl::Storage> TStoragePool;

  class ResourceManager
  {
  public:

    struct StoragePoolParams
    {
      size_t m_vbSize;
      size_t m_vertexSize;
      size_t m_ibSize;
      size_t m_indexSize;
      size_t m_storagesCount;
      EStorageType m_storageType;
      bool m_isDebugging;

      StoragePoolParams();
      StoragePoolParams(EStorageType storageType);
      StoragePoolParams(size_t vbSize,
                        size_t vertexSize,
                        size_t ibSize,
                        size_t indexSize,
                        size_t storagesCount,
                        EStorageType storageType,
                        bool isDebugging);

      bool isValid() const;
    };

    struct TexturePoolParams
    {
      size_t m_texWidth;
      size_t m_texHeight;
      size_t m_texCount;
      graphics::DataFormat m_format;
      ETextureType m_textureType;
      bool m_isDebugging;

      TexturePoolParams();
      TexturePoolParams(ETextureType textureType);
      TexturePoolParams(size_t texWidth,
                        size_t texHeight,
                        size_t texCount,
                        graphics::DataFormat format,
                        ETextureType textureType,
                        bool isDebugging);

      bool isValid() const;
    };

    struct GlyphCacheParams
    {
      string m_unicodeBlockFile;
      string m_whiteListFile;
      string m_blackListFile;

      size_t m_glyphCacheMemoryLimit;

      GlyphCacheParams();
      GlyphCacheParams(string const & unicodeBlockFile,
                       string const & whiteListFile,
                       string const & blackListFile,
                       size_t glyphCacheMemoryLimit);
    };

    struct Params
    {
    private:

      string m_vendorName;
      string m_rendererName;

      /// check non-strict matching upon vendorName and rendererName
      bool isGPU(char const * vendorName, char const * rendererName, bool strictMatch) const;

    public:

      DataFormat m_rtFormat;
      DataFormat m_texFormat;
      DataFormat m_texRtFormat;
      bool m_useSingleThreadedOGL;
      bool m_useReadPixelsToSynchronize;

      size_t m_videoMemoryLimit;

      /// storages params
      vector<StoragePoolParams> m_storageParams;

      /// textures params
      vector<TexturePoolParams> m_textureParams;

      /// glyph caches params
      GlyphCacheParams m_glyphCacheParams;

      unsigned m_renderThreadsCount;
      unsigned m_threadSlotsCount;

      Params();

      void distributeFreeMemory(int freeVideoMemory);
      void checkDeviceCaps();
      int memoryUsage() const;
      int fixedMemoryUsage() const;
      void initScaleWeights();
    };

  private:

    typedef map<string, shared_ptr<gl::BaseTexture> > TStaticTextures;

    TStaticTextures m_staticTextures;

    threads::Mutex m_mutex;

    vector<shared_ptr<TTexturePool> > m_texturePools;
    vector<shared_ptr<TStoragePool> > m_storagePools;

    struct ThreadSlot
    {
      shared_ptr<gl::ProgramManager> m_programManager;
      shared_ptr<GlyphCache> m_glyphCache;
    };

    vector<ThreadSlot> m_threadSlots;

    Params m_params;

  public:

    ResourceManager(Params const & p);

    void initThreadSlots(Params const & p);

    void initStoragePool(StoragePoolParams const & p, shared_ptr<TStoragePool> & pool);

    TStoragePool * storagePool(EStorageType type);

    void initTexturePool(TexturePoolParams const & p, shared_ptr<TTexturePool> & pool);

    TTexturePool * texturePool(ETextureType type);

    shared_ptr<gl::BaseTexture> const & getTexture(string const & fileName);

    Params const & params() const;

    GlyphCache * glyphCache(int threadSlot = 0);

    int renderThreadSlot(int threadNum) const;
    int guiThreadSlot() const;
    int cacheThreadSlot() const;

    void addFonts(vector<string> const & fontNames);

    void memoryWarning();
    void enterBackground();
    void enterForeground();

    void updatePoolState();

    void cancel();

    bool useReadPixelsToSynchronize() const;

    shared_ptr<graphics::gl::BaseTexture> createRenderTarget(unsigned w, unsigned h);
    gl::ProgramManager * programManager(int threadSlot);
  };

  void loadSkin(shared_ptr<ResourceManager> const & rm,
                string const & fileName,
                vector<shared_ptr<ResourceCache> > & caches);
}

<|endoftext|>


<commit_before>/*
Copyright (C) 2011-2015 Yubico AB.  All rights reserved.

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

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

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

#include "scanedit.h"
#include "yubikeyutil.h"
#include "common.h"

#include <QDebug>

ScanEdit::ScanEdit() {
}

QString ScanEdit::textToScanCodes(const QString text) {
    QString scanCode;
    for(int i = 0; i < text.length(); i++) {
        QChar ch = text.at(i);
        unsigned char code = 0;
        if(ch == '\\') {
            if(i + 1 != text.length()) {
                QChar next = text.at(i + 1);
                if(next == '\\') {
                    i++;
                } else if(next == 't') {
                    i++;
                    ch = '\t';
                } else if(next == 'n') {
                    i++;
                    ch = '\n';
                }
            }
        }
        if(code == 0) {
            qDebug() << "evaluating" << ch << (int)ch.toLatin1();
            code = keyMap.value(ch.toLatin1() & 0xff, 0);
        }
        QString hexTxt = YubiKeyUtil::qstrHexEncode(&code, 1);
        scanCode += hexTxt;
    }
    return scanCode;
}

QString ScanEdit::scanCodesToText(const QString scanCode) {
    QString text;
    for(int i = 0; i < scanCode.length(); i += 2) {
        bool ok;
        unsigned int code = scanCode.mid(i, 2).toUInt(&ok, 16);
        if(ok == true) {
            QString key;
            key += keyMap.key(code, 0);
            if(key == "\n") key = "\\n";
            if(key == "\t") key = "\\t";
            if(key == "\\") key = "\\\\";
            text += key;
        }
    }
    return text;
}
<commit_msg>remove debugging for every encode case and add debug for failure<commit_after>/*
Copyright (C) 2011-2015 Yubico AB.  All rights reserved.

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

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

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

#include "scanedit.h"
#include "yubikeyutil.h"
#include "common.h"

#include <QDebug>

ScanEdit::ScanEdit() {
}

QString ScanEdit::textToScanCodes(const QString text) {
    QString scanCode;
    for(int i = 0; i < text.length(); i++) {
        QChar ch = text.at(i);
        unsigned char code = 0;
        if(ch == '\\') {
            if(i + 1 != text.length()) {
                QChar next = text.at(i + 1);
                if(next == '\\') {
                    i++;
                } else if(next == 't') {
                    i++;
                    ch = '\t';
                } else if(next == 'n') {
                    i++;
                    ch = '\n';
                }
            }
        }
        code = keyMap.value(ch.toLatin1() & 0xff, 0);
        if(code == 0) {
            qDebug() << "no mapping for" << ch;
        }
        QString hexTxt = YubiKeyUtil::qstrHexEncode(&code, 1);
        scanCode += hexTxt;
    }
    return scanCode;
}

QString ScanEdit::scanCodesToText(const QString scanCode) {
    QString text;
    for(int i = 0; i < scanCode.length(); i += 2) {
        bool ok;
        unsigned int code = scanCode.mid(i, 2).toUInt(&ok, 16);
        if(ok == true) {
            QString key;
            key += keyMap.key(code, 0);
            if(key == "\n") key = "\\n";
            if(key == "\t") key = "\\t";
            if(key == "\\") key = "\\\\";
            text += key;
        }
    }
    return text;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */
#include <libport/cstdlib>
#include <iostream>

#include <libport/bind.hh>
#include <boost/lambda/lambda.hpp>
#include <boost/mem_fn.hpp>

#include <libport/compiler.hh>     // For LIBPORT_DEBUG
#include <libport/containers.hh>
#include <libport/debug.hh>
#include <libport/foreach.hh>
#include <libport/indent.hh>
#include <libport/separate.hh>

#include <sched/job.hh>

GD_ADD_CATEGORY(sched);

namespace sched
{
  StopException::StopException(unsigned depth, boost::any payload)
    : depth_(depth)
    , payload_(payload)
  {
  }

  /*-------------------------.
  | Job::ChildrenCollector.  |
  `-------------------------*/

  Job::ChildrenCollector::~ChildrenCollector()
  {
    foreach (rJob& child, *this)
      parent_->terminate_child(child);
  }

  void
  Job::ChildrenCollector::collect()
  {
    for (iterator i = begin(); i != end(); /* nothing. */)
      if ((*i)->terminated())
        {
          parent_->terminate_child(*i);
          i = erase(i);
        }
      else
        ++i;
  }

  std::ostream&
  Job::ChildrenCollector::dump(std::ostream& o) const
  {
    // Explicit parameters required by MSWC 2005.
    return o << "{" << libport::incendl
             << libport::separate(*this, libport::iendl)
             << libport::decendl << "}";
  }

  std::ostream&
  operator<< (std::ostream& o, const Job::ChildrenCollector& c)
  {
    return c.dump(o);
  }

  /*------.
  | Job.  |
  `------*/

  unsigned int Job::alive_jobs_ = 0;

  std::ostream&
  Job::dump(std::ostream& o) const
  {
    o << "Job(" << name_ << ")"
      << " "
      << (child_job() ? "child job" : "root job")
      << " state: " << state_;
    if (!children_.empty())
      o << " Children:" << libport::incendl
        << "{" << libport::incendl
        << children_ << libport::decendl
        << "}" << libport::decindent;
    return o;
  }

  void
  Job::run()
  {
    GD_CATEGORY(sched);
    assert(state_ == to_start);
    LIBPORT_DEBUG("In Job::run for " << this);

    // We may get interrupted during our first run, in which case
    // we better not be in the to_start state while we are executing
    // or we would get removed abruptly from the scheduler pending_
    // list.
    state_ = running;
    try {
      if (has_pending_exception() &&
	  dynamic_cast<SchedulerException*>(pending_exception_.get()))
	check_for_pending_exception();
      work();
    }
    catch (TerminateException&)
    {
      // Normal termination requested.
    }
    catch (StopException&)
    {
      // Termination through "stop" or "block" on a top-level tag,
      // that is a tag inherited at the job creation time.
    }
    catch (const exception& e)
    {
      // Rethrow the exception into the parent job if it exists.
      if (parent_)
	parent_->async_throw(ChildException(e.clone()));
    }
    catch (const std::exception& e)
    {
      // Exception is lost and cannot be propagated properly but can
      // be printed onto the console for diagnostic purpose.
      GD_FERROR("job %s: Exception `%s' caught, losing it",
                (this)(e.what()));
    }
    catch (...)
    {
      // Exception is lost and cannot be propagated properly.
      GD_FERROR("job %s: Unknown exception caught, losing it",
                (this));
    }

    terminate_cleanup();

    // We should never go there as the scheduler will have terminated us.
    pabort("scheduler did not terminate us");
  }

  void
  Job::terminate_now()
  {
    // We have to terminate our children as well.
    terminate_jobs(children_);
    terminate_asap();
  }

  void
  Job::terminate_asap()
  {
    if (!terminated())
      async_throw(TerminateException());
  }

  void
  Job::terminate_child(const rJob& child)
  {
    child->terminate_now();
    libport::erase_if(children_, boost::lambda::_1 == child);
  }

  void
  Job::terminate_cleanup()
  {
    // Wake-up waiting jobs.
    foreach (const rJob& job, to_wake_up_)
      if (!job->terminated())
	job->state_set(running);
    to_wake_up_.clear();
    state_ = zombie;
    scheduler_.resume_scheduler(this);
  }

  void
  Job::register_child(const rJob& child, ChildrenCollector& children)
  {
    assert(!child->parent_);
    child->parent_ = this;
    children.push_back(child);
    children_.push_back(child);
  }

  static bool
  job_compare(rJob lhs, rJob rhs)
  {
    return lhs == rhs;
  }

  void
  Job::yield_until_terminated(Job& other)
  {
    if (non_interruptible_ && this != &other)
      scheduling_error
	("dependency on other task in non-interruptible code");

    if (!other.terminated())
    {
      // We allow enqueuing on ourselves, but without doing it for real.
      if (&other != this)
	other.to_wake_up_.push_back(this);
      state_ = joining;
      try
      {
	scheduler_.resume_scheduler(this);
      }
      catch (...)
      {
	// We have been awoken by an exception; in this case,
	// dequeue ourselves from the other thread queue if
	// we are still enqueued there.
	libport::erase_if(other.to_wake_up_,
                          boost::bind(job_compare, this, _1));
	throw;
      }
    }
  }

  void
  Job::yield_until_terminated(const jobs_type& jobs)
  {
    foreach (const rJob& job, jobs)
      yield_until_terminated(*job);
  }

  void
  Job::yield_until_things_changed()
  {
    if (non_interruptible_ && !frozen())
      scheduling_error
	("attempt to wait for condition changes in non-interruptible code");

    state_ = waiting;
    scheduler_.resume_scheduler(this);
  }

  void
  Job::async_throw(const exception& e)
  {
    // A job which has received an exception is no longer side effect
    // free or non-interruptible.
    side_effect_free_ = false;
    non_interruptible_ = false;
    // If this is the current job we are talking about, the exception
    // is synchronous.
    if (scheduler_.is_current_job(this))
      e.rethrow();

    // Store the exception for later use.
    pending_exception_ = e.clone();

    // Now that we acquired an exception to raise, we are active again,
    // even if we were previously sleeping or waiting for something.
    if (state_ != to_start && state_ != zombie)
      state_ = running;
  }

  void
  Job::register_stopped_tag(const Tag& tag, const boost::any& payload)
  {
    size_t max_tag_check = (size_t)-1;
    if (has_pending_exception())
    {
      // If we are going to terminate, do nothing
      if (dynamic_cast<TerminateException*>(pending_exception_.get()))
	return;
      // If we already have a StopException stored, do not go any
      // further.
      StopException* exc =
	dynamic_cast<StopException*>(pending_exception_.get());
      if (exc)
	max_tag_check = exc->depth_get();
    }

    // Check if we are affected by this tag, up-to max_tag_check from
    // the beginning of the tag list.
    if (size_t pos = has_tag(tag, max_tag_check))
      async_throw(StopException(pos - 1, payload));
  }

  void
  Job::check_for_pending_exception()
  {
    // If an exception has been stored for further rethrow, now is
    // a good time to do so.
    if (has_pending_exception())
    {
      // Reset pending_exception_ by copying it into a local variable
      // first. This ensures that the exception will be destroyed
      // properly after having been rethrown.
      exception_ptr e = pending_exception_;
      e->rethrow();
    }
  }

  unsigned int
  Job::alive_jobs()
  {
    return alive_jobs_;
  }

  /*------------.
  | jobs_type.  |
  `------------*/

  void
  terminate_jobs(jobs_type& jobs)
  {
    foreach (rJob& job, jobs)
      job->terminate_now();
    jobs.clear();
  }

  std::ostream&
  operator<< (std::ostream& o, const jobs_type& js)
  {
    // Explicit parameters required by MSWC 2005.
    return o << libport::separate<const jobs_type,
                                  std::ostream&(*)(std::ostream&)>
                                 (js, libport::iendl);
  }

} // namespace sched
<commit_msg>MSVC: parametric functions.<commit_after>/*
 * Copyright (C) 2009, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */
#include <libport/cstdlib>
#include <iostream>

#include <libport/bind.hh>
#include <boost/lambda/lambda.hpp>
#include <boost/mem_fn.hpp>

#include <libport/compiler.hh>     // For LIBPORT_DEBUG
#include <libport/containers.hh>
#include <libport/debug.hh>
#include <libport/foreach.hh>
#include <libport/indent.hh>
#include <libport/separate.hh>

#include <sched/job.hh>

GD_ADD_CATEGORY(sched);

namespace sched
{
  StopException::StopException(unsigned depth, boost::any payload)
    : depth_(depth)
    , payload_(payload)
  {
  }

  /*-------------------------.
  | Job::ChildrenCollector.  |
  `-------------------------*/

  Job::ChildrenCollector::~ChildrenCollector()
  {
    foreach (rJob& child, *this)
      parent_->terminate_child(child);
  }

  void
  Job::ChildrenCollector::collect()
  {
    for (iterator i = begin(); i != end(); /* nothing. */)
      if ((*i)->terminated())
        {
          parent_->terminate_child(*i);
          i = erase(i);
        }
      else
        ++i;
  }

  std::ostream&
  Job::ChildrenCollector::dump(std::ostream& o) const
  {
    return o << "{" << libport::incendl
             // Explicit parameters required by MSWC 2005.
             << libport::separate<const ChildrenCollector,
                                  std::ostream&(*)(std::ostream&)>
                                  (*this, libport::iendl)
             << libport::decendl << "}";
  }

  std::ostream&
  operator<< (std::ostream& o, const Job::ChildrenCollector& c)
  {
    return c.dump(o);
  }

  /*------.
  | Job.  |
  `------*/

  unsigned int Job::alive_jobs_ = 0;

  std::ostream&
  Job::dump(std::ostream& o) const
  {
    o << "Job(" << name_ << ")"
      << " "
      << (child_job() ? "child job" : "root job")
      << " state: " << state_;
    if (!children_.empty())
      o << " Children:" << libport::incendl
        << "{" << libport::incendl
        << children_ << libport::decendl
        << "}" << libport::decindent;
    return o;
  }

  void
  Job::run()
  {
    GD_CATEGORY(sched);
    assert(state_ == to_start);
    LIBPORT_DEBUG("In Job::run for " << this);

    // We may get interrupted during our first run, in which case
    // we better not be in the to_start state while we are executing
    // or we would get removed abruptly from the scheduler pending_
    // list.
    state_ = running;
    try {
      if (has_pending_exception() &&
	  dynamic_cast<SchedulerException*>(pending_exception_.get()))
	check_for_pending_exception();
      work();
    }
    catch (TerminateException&)
    {
      // Normal termination requested.
    }
    catch (StopException&)
    {
      // Termination through "stop" or "block" on a top-level tag,
      // that is a tag inherited at the job creation time.
    }
    catch (const exception& e)
    {
      // Rethrow the exception into the parent job if it exists.
      if (parent_)
	parent_->async_throw(ChildException(e.clone()));
    }
    catch (const std::exception& e)
    {
      // Exception is lost and cannot be propagated properly but can
      // be printed onto the console for diagnostic purpose.
      GD_FERROR("job %s: Exception `%s' caught, losing it",
                (this)(e.what()));
    }
    catch (...)
    {
      // Exception is lost and cannot be propagated properly.
      GD_FERROR("job %s: Unknown exception caught, losing it",
                (this));
    }

    terminate_cleanup();

    // We should never go there as the scheduler will have terminated us.
    pabort("scheduler did not terminate us");
  }

  void
  Job::terminate_now()
  {
    // We have to terminate our children as well.
    terminate_jobs(children_);
    terminate_asap();
  }

  void
  Job::terminate_asap()
  {
    if (!terminated())
      async_throw(TerminateException());
  }

  void
  Job::terminate_child(const rJob& child)
  {
    child->terminate_now();
    libport::erase_if(children_, boost::lambda::_1 == child);
  }

  void
  Job::terminate_cleanup()
  {
    // Wake-up waiting jobs.
    foreach (const rJob& job, to_wake_up_)
      if (!job->terminated())
	job->state_set(running);
    to_wake_up_.clear();
    state_ = zombie;
    scheduler_.resume_scheduler(this);
  }

  void
  Job::register_child(const rJob& child, ChildrenCollector& children)
  {
    assert(!child->parent_);
    child->parent_ = this;
    children.push_back(child);
    children_.push_back(child);
  }

  static bool
  job_compare(rJob lhs, rJob rhs)
  {
    return lhs == rhs;
  }

  void
  Job::yield_until_terminated(Job& other)
  {
    if (non_interruptible_ && this != &other)
      scheduling_error
	("dependency on other task in non-interruptible code");

    if (!other.terminated())
    {
      // We allow enqueuing on ourselves, but without doing it for real.
      if (&other != this)
	other.to_wake_up_.push_back(this);
      state_ = joining;
      try
      {
	scheduler_.resume_scheduler(this);
      }
      catch (...)
      {
	// We have been awoken by an exception; in this case,
	// dequeue ourselves from the other thread queue if
	// we are still enqueued there.
	libport::erase_if(other.to_wake_up_,
                          boost::bind(job_compare, this, _1));
	throw;
      }
    }
  }

  void
  Job::yield_until_terminated(const jobs_type& jobs)
  {
    foreach (const rJob& job, jobs)
      yield_until_terminated(*job);
  }

  void
  Job::yield_until_things_changed()
  {
    if (non_interruptible_ && !frozen())
      scheduling_error
	("attempt to wait for condition changes in non-interruptible code");

    state_ = waiting;
    scheduler_.resume_scheduler(this);
  }

  void
  Job::async_throw(const exception& e)
  {
    // A job which has received an exception is no longer side effect
    // free or non-interruptible.
    side_effect_free_ = false;
    non_interruptible_ = false;
    // If this is the current job we are talking about, the exception
    // is synchronous.
    if (scheduler_.is_current_job(this))
      e.rethrow();

    // Store the exception for later use.
    pending_exception_ = e.clone();

    // Now that we acquired an exception to raise, we are active again,
    // even if we were previously sleeping or waiting for something.
    if (state_ != to_start && state_ != zombie)
      state_ = running;
  }

  void
  Job::register_stopped_tag(const Tag& tag, const boost::any& payload)
  {
    size_t max_tag_check = (size_t)-1;
    if (has_pending_exception())
    {
      // If we are going to terminate, do nothing
      if (dynamic_cast<TerminateException*>(pending_exception_.get()))
	return;
      // If we already have a StopException stored, do not go any
      // further.
      StopException* exc =
	dynamic_cast<StopException*>(pending_exception_.get());
      if (exc)
	max_tag_check = exc->depth_get();
    }

    // Check if we are affected by this tag, up-to max_tag_check from
    // the beginning of the tag list.
    if (size_t pos = has_tag(tag, max_tag_check))
      async_throw(StopException(pos - 1, payload));
  }

  void
  Job::check_for_pending_exception()
  {
    // If an exception has been stored for further rethrow, now is
    // a good time to do so.
    if (has_pending_exception())
    {
      // Reset pending_exception_ by copying it into a local variable
      // first. This ensures that the exception will be destroyed
      // properly after having been rethrown.
      exception_ptr e = pending_exception_;
      e->rethrow();
    }
  }

  unsigned int
  Job::alive_jobs()
  {
    return alive_jobs_;
  }

  /*------------.
  | jobs_type.  |
  `------------*/

  void
  terminate_jobs(jobs_type& jobs)
  {
    foreach (rJob& job, jobs)
      job->terminate_now();
    jobs.clear();
  }

  std::ostream&
  operator<< (std::ostream& o, const jobs_type& js)
  {
    // Explicit parameters required by MSWC 2005.
    return o << libport::separate<const jobs_type,
                                  std::ostream&(*)(std::ostream&)>
                                 (js, libport::iendl);
  }

} // namespace sched
<|endoftext|>


<commit_before>/*
 * integer.cpp
 */
#include "integer.h"

namespace c8 {
    /*
     * Construct an integer using a string.
     *
     * The string can have an optional '-' sign to indicate that it's negative,
     * and then the usual C++-like hex, octal, * or decimal representations.
     */
    integer::integer(const std::string &v) {
        negative_ = false;

        /*
         * Does our integer have a '-' sign?
         */
        if (v.length()) {
            if (v[0] == '-') {
                negative_ = true;
            }
        }

        magnitude_ = natural(negative_ ? v.substr(1) : v);
    }

    /*
     * Add another integer to this one.
     */
    auto integer::operator +(const integer &v) const -> integer {
        /*
         * If our two numbers have the same sign then we just add and retain the
         * sign for this number.
         */
        if (negative_ == v.negative_) {
            integer res;
            res.negative_ = negative_;
            res.magnitude_ = magnitude_ + v.magnitude_;
            return res;
        }

        /*
         * If we are adding a larger magnitude value then subtract the smaller
         * from the larger, and retain the sign of the larger.
         */
        if (magnitude_ < v.magnitude_) {
            integer res;
            res.negative_ = v.negative_;
            res.magnitude_ = v.magnitude_ - magnitude_;
            return res;
        }

        /*
         * We're adding a smaller magnitude value, so subtract the smaller
         * from the larger, and, again, retain the sign of the larger.
         */
        integer res;
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ - v.magnitude_;
        return res;
    }

    /*
     * Subtract another integer from this one.
     *
     * Note that there is a subtle difference between the integer subtract operation
     * and the natural number version:  We don't have to worry about throwing
     * exceptions for negative results.
     */
    auto integer::operator -(const integer &v) const -> integer {
        /*
         * If we're subtracting a negative number from a positive, or a positive from
         * a negative, then we add the magnitudes of both and retain the sign of this one.
         */
        if (negative_ != v.negative_) {
            integer res;
            res.negative_ = negative_;
            res.magnitude_ = magnitude_ + v.magnitude_;
            return res;
        }

        /*
         * If we're subtracting a number that has a larger magnitude than this one, then
         * subtract the magnitudes and use the inverse of the sign for the larger.
         */
        if (magnitude_ < v.magnitude_) {
            integer res;
            res.negative_ = !v.negative_;
            res.magnitude_ = v.magnitude_ - magnitude_;
            return res;
        }

        /*
         * We're subtracting a number with a smaller magnitude than this one, so subtract
         * the magnitudes and use the sign of this one.
         */
        integer res;
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ - v.magnitude_;
        return res;
    }

    /*
     * Left shift this integer by a number of bits.
     */
    auto integer::operator <<(unsigned int count) const -> integer {
        integer res;
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ << count;
        return res;
    }

    /*
     * Right shift this integer by a number of bits.
     */
    auto integer::operator >>(unsigned int count) const -> integer {
        integer res;
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ >> count;
        return res;
    }

    /*
     * Multiply another integer with this one.
     */
    auto integer::operator *(const integer &v) const -> integer {
        integer res;
        res.negative_ = negative_ ^ v.negative_;
        res.magnitude_ = magnitude_ * v.magnitude_;
        return res;
    }

    /*
     * Divide this integer by another one, returning the quotient and modulus.
     */
    auto integer::divide_modulus(const integer &v) const -> std::pair<integer, integer> {
        std::pair<natural, natural> dm = magnitude_.divide_modulus(v.magnitude_);

        integer div_res;
        div_res.negative_ = negative_ ^ v.negative_;
        div_res.magnitude_ = dm.first;

        integer mod_res;
        mod_res.magnitude_ = dm.second;
        return std::make_pair(div_res, mod_res);
    }

    /*
     * Compare a integer with this one.
     */
    auto integer::compare(const integer &v) const -> comparison {
        /*
         * Is this number non-negative?
         */
        if (!negative_) {
            /*
             * If the number we're comparing with is non-negative too then we can
             * just do a simple comparison of the magnitudes.
             */
            if (!v.negative_) {
                return magnitude_.compare(v.magnitude_);
            }

            /*
             * The number we're comparing with is negative so we're definitely greater
             * than it.
             */
            return comparison::gt;
        }

        /*
         * This integer is negative, so if the number we're comparing with is also
         * negative then we compare magnitudes, but we reverse the result.  The most
         * negative value is smaller, not larger.
         */
        if (v.negative_) {
            auto ures = magnitude_.compare(v.magnitude_);
            switch (ures) {
            case comparison::lt:
                return comparison::gt;

            case comparison::eq:
                return comparison::eq;

            case comparison::gt:
                return comparison::lt;
            }
        }

        /*
         * This integer is negative, but the one we're comparing with is not, so we're
         * smaller.
         */
        return comparison::lt;
    }

    /*
     * Convert this integer to a long long.
     */
    auto integer::to_long_long() const -> long long {
        /*
         * Will this number fit in a long long?  If not then throw an exception.
         */
        if (magnitude_.count_bits() > ((8 * sizeof(long long)) - 1)) {
            throw overflow_error();
        }

        /*
         * Convert the result, and, if necessary, flip the sign.
         */
        long long res = static_cast<long long>(to_unsigned_long_long(magnitude_));

        if (negative_) {
            res = -res;
        }

        return res;
    }

    /*
     * << operator to print a integer.
     */
    auto operator <<(std::ostream &outstr, const integer &v) -> std::ostream & {
        if (v.negative_) {
            outstr << '-';
        }

        outstr << v.magnitude_;

        return outstr;
    }
}

<commit_msg>Improve RVO handling<commit_after>/*
 * integer.cpp
 */
#include "integer.h"

namespace c8 {
    /*
     * Construct an integer using a string.
     *
     * The string can have an optional '-' sign to indicate that it's negative,
     * and then the usual C++-like hex, octal, * or decimal representations.
     */
    integer::integer(const std::string &v) {
        negative_ = false;

        /*
         * Does our integer have a '-' sign?
         */
        if (v.length()) {
            if (v[0] == '-') {
                negative_ = true;
            }
        }

        magnitude_ = natural(negative_ ? v.substr(1) : v);
    }

    /*
     * Add another integer to this one.
     */
    auto integer::operator +(const integer &v) const -> integer {
        integer res;

        /*
         * If our two numbers have the same sign then we just add and retain the
         * sign for this number.
         */
        if (negative_ == v.negative_) {
            res.negative_ = negative_;
            res.magnitude_ = magnitude_ + v.magnitude_;
            return res;
        }

        /*
         * If we are adding a larger magnitude value then subtract the smaller
         * from the larger, and retain the sign of the larger.
         */
        if (magnitude_ < v.magnitude_) {
            res.negative_ = v.negative_;
            res.magnitude_ = v.magnitude_ - magnitude_;
            return res;
        }

        /*
         * We're adding a smaller magnitude value, so subtract the smaller
         * from the larger, and, again, retain the sign of the larger.
         */
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ - v.magnitude_;
        return res;
    }

    /*
     * Subtract another integer from this one.
     *
     * Note that there is a subtle difference between the integer subtract operation
     * and the natural number version:  We don't have to worry about throwing
     * exceptions for negative results.
     */
    auto integer::operator -(const integer &v) const -> integer {
        integer res;

        /*
         * If we're subtracting a negative number from a positive, or a positive from
         * a negative, then we add the magnitudes of both and retain the sign of this one.
         */
        if (negative_ != v.negative_) {
            res.negative_ = negative_;
            res.magnitude_ = magnitude_ + v.magnitude_;
            return res;
        }

        /*
         * If we're subtracting a number that has a larger magnitude than this one, then
         * subtract the magnitudes and use the inverse of the sign for the larger.
         */
        if (magnitude_ < v.magnitude_) {
            res.negative_ = !v.negative_;
            res.magnitude_ = v.magnitude_ - magnitude_;
            return res;
        }

        /*
         * We're subtracting a number with a smaller magnitude than this one, so subtract
         * the magnitudes and use the sign of this one.
         */
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ - v.magnitude_;
        return res;
    }

    /*
     * Left shift this integer by a number of bits.
     */
    auto integer::operator <<(unsigned int count) const -> integer {
        integer res;
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ << count;
        return res;
    }

    /*
     * Right shift this integer by a number of bits.
     */
    auto integer::operator >>(unsigned int count) const -> integer {
        integer res;
        res.negative_ = negative_;
        res.magnitude_ = magnitude_ >> count;
        return res;
    }

    /*
     * Multiply another integer with this one.
     */
    auto integer::operator *(const integer &v) const -> integer {
        integer res;
        res.negative_ = negative_ ^ v.negative_;
        res.magnitude_ = magnitude_ * v.magnitude_;
        return res;
    }

    /*
     * Divide this integer by another one, returning the quotient and modulus.
     */
    auto integer::divide_modulus(const integer &v) const -> std::pair<integer, integer> {
        std::pair<natural, natural> dm = magnitude_.divide_modulus(v.magnitude_);

        integer div_res;
        div_res.negative_ = negative_ ^ v.negative_;
        div_res.magnitude_ = dm.first;

        integer mod_res;
        mod_res.magnitude_ = dm.second;
        return std::make_pair(div_res, mod_res);
    }

    /*
     * Compare a integer with this one.
     */
    auto integer::compare(const integer &v) const -> comparison {
        /*
         * Is this number non-negative?
         */
        if (!negative_) {
            /*
             * If the number we're comparing with is non-negative too then we can
             * just do a simple comparison of the magnitudes.
             */
            if (!v.negative_) {
                return magnitude_.compare(v.magnitude_);
            }

            /*
             * The number we're comparing with is negative so we're definitely greater
             * than it.
             */
            return comparison::gt;
        }

        /*
         * This integer is negative, so if the number we're comparing with is also
         * negative then we compare magnitudes, but we reverse the result.  The most
         * negative value is smaller, not larger.
         */
        if (v.negative_) {
            auto ures = magnitude_.compare(v.magnitude_);
            switch (ures) {
            case comparison::lt:
                return comparison::gt;

            case comparison::eq:
                return comparison::eq;

            case comparison::gt:
                return comparison::lt;
            }
        }

        /*
         * This integer is negative, but the one we're comparing with is not, so we're
         * smaller.
         */
        return comparison::lt;
    }

    /*
     * Convert this integer to a long long.
     */
    auto integer::to_long_long() const -> long long {
        /*
         * Will this number fit in a long long?  If not then throw an exception.
         */
        if (magnitude_.count_bits() > ((8 * sizeof(long long)) - 1)) {
            throw overflow_error();
        }

        /*
         * Convert the result, and, if necessary, flip the sign.
         */
        long long res = static_cast<long long>(to_unsigned_long_long(magnitude_));

        if (negative_) {
            res = -res;
        }

        return res;
    }

    /*
     * << operator to print a integer.
     */
    auto operator <<(std::ostream &outstr, const integer &v) -> std::ostream & {
        if (v.negative_) {
            outstr << '-';
        }

        outstr << v.magnitude_;

        return outstr;
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "bindings/core/v8/DictionaryHelperForBindings.h"
#include "bindings/core/v8/ExceptionMessages.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/modules/v8/V8Gamepad.h"
#include "bindings/modules/v8/V8Headers.h"
#include "bindings/modules/v8/V8MIDIPort.h"
#include "bindings/modules/v8/V8MediaStream.h"
#include "bindings/modules/v8/V8SpeechRecognitionResult.h"
#include "bindings/modules/v8/V8SpeechRecognitionResultList.h"
#include "modules/gamepad/Gamepad.h"
#include "modules/mediastream/MediaStream.h"
#include "modules/speech/SpeechRecognitionResult.h"
#include "modules/speech/SpeechRecognitionResultList.h"

namespace blink {

template <>
struct DictionaryHelperTraits<MIDIPort> {
    typedef V8MIDIPort type;
};

template <>
struct DictionaryHelperTraits<SpeechRecognitionResult> {
    typedef V8SpeechRecognitionResult type;
};

template <>
struct DictionaryHelperTraits<SpeechRecognitionResultList> {
    typedef V8SpeechRecognitionResultList type;
};

template <>
struct DictionaryHelperTraits<Gamepad> {
    typedef V8Gamepad type;
};

template <>
struct DictionaryHelperTraits<MediaStream> {
    typedef V8MediaStream type;
};

template <>
struct DictionaryHelperTraits<Headers> {
    typedef V8Headers type;
};

template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<MIDIPort>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<SpeechRecognitionResult>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<SpeechRecognitionResultList>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<Gamepad>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<MediaStream>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, RefPtrWillBeMember<Headers>& value);

template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<MIDIPort>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<SpeechRecognitionResult>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<SpeechRecognitionResultList>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<Gamepad>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<MediaStream>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, RefPtrWillBeMember<Headers>& value);

} // namespace blink
<commit_msg>Remove dictionary helper functions installation for SpeechRecognitionResult<commit_after>/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "bindings/core/v8/DictionaryHelperForBindings.h"
#include "bindings/core/v8/ExceptionMessages.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/modules/v8/V8Gamepad.h"
#include "bindings/modules/v8/V8Headers.h"
#include "bindings/modules/v8/V8MIDIPort.h"
#include "bindings/modules/v8/V8MediaStream.h"
#include "bindings/modules/v8/V8SpeechRecognitionResult.h"
#include "bindings/modules/v8/V8SpeechRecognitionResultList.h"
#include "modules/gamepad/Gamepad.h"
#include "modules/mediastream/MediaStream.h"
#include "modules/speech/SpeechRecognitionResult.h"
#include "modules/speech/SpeechRecognitionResultList.h"

namespace blink {

template <>
struct DictionaryHelperTraits<MIDIPort> {
    typedef V8MIDIPort type;
};

template <>
struct DictionaryHelperTraits<SpeechRecognitionResultList> {
    typedef V8SpeechRecognitionResultList type;
};

template <>
struct DictionaryHelperTraits<Gamepad> {
    typedef V8Gamepad type;
};

template <>
struct DictionaryHelperTraits<MediaStream> {
    typedef V8MediaStream type;
};

template <>
struct DictionaryHelperTraits<Headers> {
    typedef V8Headers type;
};

template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<MIDIPort>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<SpeechRecognitionResultList>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<Gamepad>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, Member<MediaStream>& value);
template bool DictionaryHelper::get(const Dictionary&, const String& key, RefPtrWillBeMember<Headers>& value);

template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<MIDIPort>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<SpeechRecognitionResultList>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<Gamepad>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, Member<MediaStream>& value);
template bool DictionaryHelper::convert(const Dictionary&, Dictionary::ConversionContext&, const String& key, RefPtrWillBeMember<Headers>& value);

} // namespace blink
<|endoftext|>


<commit_before>#include <iostream>
#define BOP_MATRIX_MULTIPLY_DISCARD_TINY
#include <bop-maths/maths.hpp>
#include "testlibs/funct_bench/funct_benchmark.hpp"
#define TEST_COUNT 1000000

using namespace bop::maths;

void bop_bench_construct() {
	Matrix<double> mat1(3);
}

void bop_bench_construct_vec() {
	Vector<double> vec(9);
}

void bop_bench_det() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	det(mat1);
}

void bop_bench_multiply() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	static Matrix<double> mat2 = {{2,3,4},{6,1,7},{3,4,5}};
	mat2 *= mat1;
}

void bop_bench_inverse_2x2() {
	static Matrix<double> mat = {{2,4},{1,7}};
	inverseMatrix(mat);
}

void bop_bench_inverse_unit() {
	static Matrix<double> mat = identityMatrix<double>(3);
	inverseMatrix(mat);
}

void bop_bench_inverse() {
	static Matrix<double> mat = {{3,2,4},{2,7,2},{-1,2,5}};
	inverseMatrix(mat);
}

void bop_bench_add() {
	static Matrix<double>mat1 = identityMatrix<double>(3);
	static Matrix<double>mat2 = identityMatrix<double>(3);
	mat1 += mat2;
}

void bop_bench_vector_add() {
	static Vector<double> vec1 = {1,2,3,4,5,6,7,8,9};
	static Vector<double> vec2 = {9,8,7,6,5,4,3,2,1};
	vec1 += vec2;
}

void bop_bench_subtract() {
	static Matrix<double>mat1 = identityMatrix<double>(3);
	static Matrix<double>mat2 = identityMatrix<double>(3);
	mat1 -= mat2;
}

void bop_bench_scalar() {
	static Matrix<double> mat = identityMatrix<double>(3);
	static double scalar = 2;
	mat *= scalar;
}

void bop_bench_scalar_div() {
	static Matrix<double> mat = identityMatrix<double>(3);
	static double scalar = 2;
	mat /= scalar;
}

void bop_bench_impose() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	static Matrix<double> mat2 = {{2,4},{6,8}};
	mat1.impose(mat2);
}

void bop_bench_compare() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	static Matrix<double> mat2 = identityMatrix<double>(3);
	mat1 == mat2;
}

int mat_tests() {
	std::cout << "\nAll matrix operations are performed on a 3 by 3 matrix unless otherwise specified" << std::endl;
	std::cout << "The result is the average operation time in nanoseconds for " << TEST_COUNT << " iterations." << std::endl;
	std::cout << "Matrix construction: " << gist::benchmark(TEST_COUNT, bop_bench_construct) << std::endl;
	std::cout << "Vector (9) construction: " << gist::benchmark(TEST_COUNT, bop_bench_construct_vec) << std::endl;
	std::cout << "Matrix multiplication: " << gist::benchmark(TEST_COUNT, bop_bench_multiply) << std::endl;
	std::cout << "Matrix determinant: " << gist::benchmark(TEST_COUNT, bop_bench_det) << std::endl;
	std::cout << "Matrix inverse (2x2): " << gist::benchmark(TEST_COUNT, bop_bench_inverse_2x2) << std::endl;
	std::cout << "Matrix inverse (unit): " << gist::benchmark(TEST_COUNT, bop_bench_inverse_unit) << std::endl;
	std::cout << "Matrix inverse: " << gist::benchmark(TEST_COUNT, bop_bench_inverse) << std::endl;
	std::cout << "Matrix addition: " << gist::benchmark(TEST_COUNT, bop_bench_add) << std::endl;
	std::cout << "Vector (9) addition: " << gist::benchmark(TEST_COUNT, bop_bench_vector_add) << std::endl;
	std::cout << "Matrix subtraction: " << gist::benchmark(TEST_COUNT, bop_bench_subtract) << std::endl;
	std::cout << "Matrix scalar multiplication: " << gist::benchmark(TEST_COUNT, bop_bench_scalar) << std::endl;
	std::cout << "Matrix scalar division: " << gist::benchmark(TEST_COUNT, bop_bench_scalar_div) << std::endl;
	std::cout << "Matrix (2x2) imposition on (3x3): " << gist::benchmark(TEST_COUNT, bop_bench_scalar_div) << std::endl;
	std::cout << "Matrix comparison (2 units): " << gist::benchmark(TEST_COUNT, bop_bench_compare) << std::endl;
	return 0;
}

int main() {
	mat_tests();
	return 0;
}
<commit_msg>expanded matrix benchmark<commit_after>#include <iostream>
#define BOP_MATRIX_MULTIPLY_DISCARD_TINY
#include <bop-maths/maths.hpp>
#include "testlibs/funct_bench/funct_benchmark.hpp"
#define TEST_COUNT 1000000

using namespace bop::maths;

void bop_bench_construct() {
	Matrix<double> mat1(3);
}

void bop_bench_constr_inlist() {
	Matrix<double> mat1 = {{1,2,3},{4,5,6},{7,8,9}};
}

void bop_bench_construct_vec() {
	Vector<double> vec(9);
}

void bop_bench_det() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	det(mat1);
}

void bop_bench_multiply() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	static Matrix<double> mat2 = {{2,3,4},{6,1,7},{3,4,5}};
	mat2 *= mat1;
}

void bop_bench_inverse_2x2() {
	static Matrix<double> mat = {{2,4},{1,7}};
	inverseMatrix(mat);
}

void bop_bench_inverse_unit() {
	static Matrix<double> mat = identityMatrix<double>(3);
	inverseMatrix(mat);
}

void bop_bench_inverse() {
	static Matrix<double> mat = {{3,2,4},{2,7,2},{-1,2,5}};
	inverseMatrix(mat);
}

void bop_bench_add() {
	static Matrix<double>mat1 = identityMatrix<double>(3);
	static Matrix<double>mat2 = identityMatrix<double>(3);
	mat1 += mat2;
}

void bop_bench_vector_add() {
	static Vector<double> vec1 = {1,2,3,4,5,6,7,8,9};
	static Vector<double> vec2 = {9,8,7,6,5,4,3,2,1};
	vec1 += vec2;
}

void bop_bench_subtract() {
	static Matrix<double>mat1 = identityMatrix<double>(3);
	static Matrix<double>mat2 = identityMatrix<double>(3);
	mat1 -= mat2;
}

void bop_bench_scalar() {
	static Matrix<double> mat = identityMatrix<double>(3);
	static double scalar = 2;
	mat *= scalar;
}

void bop_bench_scalar_div() {
	static Matrix<double> mat = identityMatrix<double>(3);
	static double scalar = 2;
	mat /= scalar;
}

void bop_bench_impose() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	static Matrix<double> mat2 = {{2,4},{6,8}};
	mat1.impose(mat2);
}

void bop_bench_compare() {
	static Matrix<double> mat1 = identityMatrix<double>(3);
	static Matrix<double> mat2 = identityMatrix<double>(3);
	mat1 == mat2;
}

int mat_tests() {
	std::cout << "\nAll matrix operations are performed on a 3 by 3 matrix unless otherwise specified" << std::endl;
	std::cout << "The result is the average operation time in nanoseconds for " << TEST_COUNT << " iterations." << std::endl;
	std::cout << "Matrix construction: " << gist::benchmark(TEST_COUNT, bop_bench_construct) << std::endl;
	std::cout << "Matrix construction by init list: " << gist::benchmark(TEST_COUNT, bop_bench_constr_inlist) << std::endl;
	std::cout << "Vector (9) construction: " << gist::benchmark(TEST_COUNT, bop_bench_construct_vec) << std::endl;
	std::cout << "Matrix multiplication: " << gist::benchmark(TEST_COUNT, bop_bench_multiply) << std::endl;
	std::cout << "Matrix determinant: " << gist::benchmark(TEST_COUNT, bop_bench_det) << std::endl;
	std::cout << "Matrix inverse (2x2): " << gist::benchmark(TEST_COUNT, bop_bench_inverse_2x2) << std::endl;
	std::cout << "Matrix inverse (unit): " << gist::benchmark(TEST_COUNT, bop_bench_inverse_unit) << std::endl;
	std::cout << "Matrix inverse: " << gist::benchmark(TEST_COUNT, bop_bench_inverse) << std::endl;
	std::cout << "Matrix addition: " << gist::benchmark(TEST_COUNT, bop_bench_add) << std::endl;
	std::cout << "Vector (9) addition: " << gist::benchmark(TEST_COUNT, bop_bench_vector_add) << std::endl;
	std::cout << "Matrix subtraction: " << gist::benchmark(TEST_COUNT, bop_bench_subtract) << std::endl;
	std::cout << "Matrix scalar multiplication: " << gist::benchmark(TEST_COUNT, bop_bench_scalar) << std::endl;
	std::cout << "Matrix scalar division: " << gist::benchmark(TEST_COUNT, bop_bench_scalar_div) << std::endl;
	std::cout << "Matrix (2x2) imposition on (3x3): " << gist::benchmark(TEST_COUNT, bop_bench_scalar_div) << std::endl;
	std::cout << "Matrix comparison (2 units): " << gist::benchmark(TEST_COUNT, bop_bench_compare) << std::endl;
	return 0;
}

int main() {
	mat_tests();
	return 0;
}
<|endoftext|>