<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

#include "Backend.h"

JITObjTypeSpecFldInfo::JITObjTypeSpecFldInfo(ObjTypeSpecFldIDL * data) :
    m_data(*data)
{
    CompileAssert(sizeof(ObjTypeSpecFldIDL) == sizeof(JITObjTypeSpecFldInfo));
}

bool
JITObjTypeSpecFldInfo::UsesAuxSlot() const
{
    return GetFlags().usesAuxSlot;
}

bool
JITObjTypeSpecFldInfo::UsesAccessor() const
{
    return GetFlags().usesAccessor;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableFieldLoad() const
{
    return GetFlags().isRootObjectNonConfigurableFieldLoad;
}

bool
JITObjTypeSpecFldInfo::HasEquivalentTypeSet() const
{
    return m_data.typeSet != nullptr;
}

bool
JITObjTypeSpecFldInfo::DoesntHaveEquivalence() const
{
    return GetFlags().doesntHaveEquivalence;
}

bool
JITObjTypeSpecFldInfo::IsPoly() const
{
    return GetFlags().isPolymorphic;
}

bool
JITObjTypeSpecFldInfo::IsMono() const
{
    return !IsPoly();
}

bool
JITObjTypeSpecFldInfo::IsBuiltIn() const
{
    return GetFlags().isBuiltIn;
}

bool
JITObjTypeSpecFldInfo::IsLoadedFromProto() const
{
    return GetFlags().isLoadedFromProto;
}

bool
JITObjTypeSpecFldInfo::HasFixedValue() const
{
    return GetFlags().hasFixedValue;
}

bool
JITObjTypeSpecFldInfo::IsBeingStored() const
{
    return GetFlags().isBeingStored;
}

bool
JITObjTypeSpecFldInfo::IsBeingAdded() const
{
    return GetFlags().isBeingAdded;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableField() const
{
    return GetFlags().isRootObjectNonConfigurableField;
}

bool
JITObjTypeSpecFldInfo::HasInitialType() const
{
    return IsMono() && !IsLoadedFromProto() && m_data.initialType != nullptr;
}

bool
JITObjTypeSpecFldInfo::IsMonoObjTypeSpecCandidate() const
{
    return IsMono();
}

bool
JITObjTypeSpecFldInfo::IsPolyObjTypeSpecCandidate() const
{
    return IsPoly();
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId() const
{
    Assert(m_data.typeId != Js::TypeIds_Limit);
    return (Js::TypeId)m_data.typeId;
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId(uint i) const
{
    Assert(IsPoly());
    return (Js::TypeId)m_data.fixedFieldInfoArray[i].type->typeId;
}

Js::PropertyId
JITObjTypeSpecFldInfo::GetPropertyId() const
{
    return (Js::PropertyId)m_data.propertyId;
}

uint16
JITObjTypeSpecFldInfo::GetSlotIndex() const
{
    return m_data.slotIndex;
}

uint16
JITObjTypeSpecFldInfo::GetFixedFieldCount() const
{
    return m_data.fixedFieldCount;
}

uint
JITObjTypeSpecFldInfo::GetObjTypeSpecFldId() const
{
    return m_data.id;
}

intptr_t
JITObjTypeSpecFldInfo::GetProtoObject() const
{
    return m_data.protoObjectAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValue(uint i) const
{
    Assert(IsPoly());
    return m_data.fixedFieldInfoArray[i].fieldValue;
}

intptr_t
JITObjTypeSpecFldInfo::GetPropertyGuardValueAddr() const
{
    return m_data.propertyGuardValueAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
{
    Assert(HasFixedValue() && GetFixedFieldCount() == 1);

    return m_data.fixedFieldInfoArray[0].fieldValue;
}

JITTimeConstructorCache *
JITObjTypeSpecFldInfo::GetCtorCache() const
{
    return (JITTimeConstructorCache*)m_data.ctorCache;
}

Js::EquivalentTypeSet *
JITObjTypeSpecFldInfo::GetEquivalentTypeSet() const
{
    return (Js::EquivalentTypeSet *)m_data.typeSet;
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType() const
{
    Assert(IsMono());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[0].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType(uint i) const
{
    Assert(IsPoly());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[i].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetInitialType() const
{
    return JITTypeHolder((JITType *)m_data.initialType);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetFirstEquivalentType() const
{
    Assert(HasEquivalentTypeSet());
    return JITTypeHolder(GetEquivalentTypeSet()->GetFirstType());
}

void
JITObjTypeSpecFldInfo::SetIsBeingStored(bool value)
{
    ((Js::ObjTypeSpecFldInfoFlags*)&m_data.flags)->isBeingStored = value;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction()
{
    Assert(HasFixedValue());
    Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
    Assert(m_data.fixedFieldInfoArray);
    if (m_data.fixedFieldInfoArray[0].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[0];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction(uint i)
{
    Assert(HasFixedValue());
    Assert(IsPoly());
    if (m_data.fixedFieldCount > 0 && m_data.fixedFieldInfoArray[i].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[i];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldInfoArray()
{
    return (JITTimeFixedField*)m_data.fixedFieldInfoArray;
}

/* static */
void
JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(
    __in ArenaAllocator * alloc,
    __in Js::ObjTypeSpecFldInfo ** objTypeSpecInfo,
    __in uint arrayLength,
    _Inout_updates_(arrayLength) ObjTypeSpecFldIDL * jitData)
{
    for (uint i = 0; i < arrayLength; ++i)
    {
        if (objTypeSpecInfo[i] == nullptr)
        {
            continue;
        }
        jitData[i].inUse = TRUE;
        if (objTypeSpecInfo[i]->IsLoadedFromProto())
        {
            jitData[i].protoObjectAddr = (intptr_t)objTypeSpecInfo[i]->GetProtoObject();
        }
        jitData[i].propertyGuardValueAddr = (intptr_t)objTypeSpecInfo[i]->GetPropertyGuard()->GetAddressOfValue();
        jitData[i].propertyId = objTypeSpecInfo[i]->GetPropertyId();
        jitData[i].typeId = objTypeSpecInfo[i]->GetTypeId();
        jitData[i].id = objTypeSpecInfo[i]->GetObjTypeSpecFldId();
        jitData[i].flags = objTypeSpecInfo[i]->GetFlags();
        jitData[i].slotIndex = objTypeSpecInfo[i]->GetSlotIndex();
        jitData[i].fixedFieldCount = objTypeSpecInfo[i]->GetFixedFieldCount();

        if (objTypeSpecInfo[i]->HasInitialType())
        {
            jitData[i].initialType = AnewStructZ(alloc, TypeIDL);
            JITType::BuildFromJsType(objTypeSpecInfo[i]->GetInitialType(), (JITType*)jitData[i].initialType);
        }

        if (objTypeSpecInfo[i]->GetCtorCache() != nullptr)
        {
            jitData[i].ctorCache = objTypeSpecInfo[i]->GetCtorCache()->GetData();
        }

        CompileAssert(sizeof(Js::EquivalentTypeSet) == sizeof(EquivalentTypeSetIDL));
        Js::EquivalentTypeSet * equivTypeSet = objTypeSpecInfo[i]->GetEquivalentTypeSet();
        if (equivTypeSet != nullptr)
        {
            jitData[i].typeSet = (EquivalentTypeSetIDL*)equivTypeSet;
        }

        jitData[i].fixedFieldInfoArraySize = jitData[i].fixedFieldCount;
        if (jitData[i].fixedFieldInfoArraySize == 0)
        {
            jitData[i].fixedFieldInfoArraySize = 1;
        }
        jitData[i].fixedFieldInfoArray = AnewArrayZ(alloc, FixedFieldIDL, jitData[i].fixedFieldInfoArraySize);
        Js::FixedFieldInfo * ffInfo = objTypeSpecInfo[i]->GetFixedFieldInfoArray();
        for (uint16 j = 0; j < jitData[i].fixedFieldInfoArraySize; ++j)
        {
            jitData[i].fixedFieldInfoArray[j].fieldValue = (intptr_t)ffInfo[j].fieldValue;
            jitData[i].fixedFieldInfoArray[j].nextHasSameFixedField = ffInfo[j].nextHasSameFixedField;
            if (ffInfo[j].fieldValue != nullptr && Js::JavascriptFunction::Is(ffInfo[j].fieldValue))
            {
                Js::JavascriptFunction * funcObj = Js::JavascriptFunction::FromVar(ffInfo[j].fieldValue);
                jitData[i].fixedFieldInfoArray[j].valueType = ValueType::FromObject(funcObj).GetRawData();
                jitData[i].fixedFieldInfoArray[j].funcInfoAddr = (intptr_t)funcObj->GetFunctionInfo();
                jitData[i].fixedFieldInfoArray[j].isClassCtor = funcObj->GetFunctionInfo()->IsConstructor();
                jitData[i].fixedFieldInfoArray[j].localFuncId = (intptr_t)funcObj->GetFunctionInfo()->GetLocalFunctionId();
                if (Js::ScriptFunction::Is(ffInfo[j].fieldValue))
                {
                    jitData[i].fixedFieldInfoArray[j].environmentAddr = (intptr_t)Js::ScriptFunction::FromVar(funcObj)->GetEnvironment();
                }
            }
            if (ffInfo[j].type != nullptr)
            {
                jitData[i].fixedFieldInfoArray[j].type = AnewStructZ(alloc, TypeIDL);
                // TODO: OOP JIT, maybe type should be out of line? might not save anything on x64 though
                JITType::BuildFromJsType(ffInfo[j].type, (JITType*)jitData[i].fixedFieldInfoArray[j].type);
            }
        }
    }
}

Js::ObjTypeSpecFldInfoFlags
JITObjTypeSpecFldInfo::GetFlags() const
{
    return (Js::ObjTypeSpecFldInfoFlags)m_data.flags;
}
<commit_msg>fix condition for fixed class ctors<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

#include "Backend.h"

JITObjTypeSpecFldInfo::JITObjTypeSpecFldInfo(ObjTypeSpecFldIDL * data) :
    m_data(*data)
{
    CompileAssert(sizeof(ObjTypeSpecFldIDL) == sizeof(JITObjTypeSpecFldInfo));
}

bool
JITObjTypeSpecFldInfo::UsesAuxSlot() const
{
    return GetFlags().usesAuxSlot;
}

bool
JITObjTypeSpecFldInfo::UsesAccessor() const
{
    return GetFlags().usesAccessor;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableFieldLoad() const
{
    return GetFlags().isRootObjectNonConfigurableFieldLoad;
}

bool
JITObjTypeSpecFldInfo::HasEquivalentTypeSet() const
{
    return m_data.typeSet != nullptr;
}

bool
JITObjTypeSpecFldInfo::DoesntHaveEquivalence() const
{
    return GetFlags().doesntHaveEquivalence;
}

bool
JITObjTypeSpecFldInfo::IsPoly() const
{
    return GetFlags().isPolymorphic;
}

bool
JITObjTypeSpecFldInfo::IsMono() const
{
    return !IsPoly();
}

bool
JITObjTypeSpecFldInfo::IsBuiltIn() const
{
    return GetFlags().isBuiltIn;
}

bool
JITObjTypeSpecFldInfo::IsLoadedFromProto() const
{
    return GetFlags().isLoadedFromProto;
}

bool
JITObjTypeSpecFldInfo::HasFixedValue() const
{
    return GetFlags().hasFixedValue;
}

bool
JITObjTypeSpecFldInfo::IsBeingStored() const
{
    return GetFlags().isBeingStored;
}

bool
JITObjTypeSpecFldInfo::IsBeingAdded() const
{
    return GetFlags().isBeingAdded;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableField() const
{
    return GetFlags().isRootObjectNonConfigurableField;
}

bool
JITObjTypeSpecFldInfo::HasInitialType() const
{
    return IsMono() && !IsLoadedFromProto() && m_data.initialType != nullptr;
}

bool
JITObjTypeSpecFldInfo::IsMonoObjTypeSpecCandidate() const
{
    return IsMono();
}

bool
JITObjTypeSpecFldInfo::IsPolyObjTypeSpecCandidate() const
{
    return IsPoly();
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId() const
{
    Assert(m_data.typeId != Js::TypeIds_Limit);
    return (Js::TypeId)m_data.typeId;
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId(uint i) const
{
    Assert(IsPoly());
    return (Js::TypeId)m_data.fixedFieldInfoArray[i].type->typeId;
}

Js::PropertyId
JITObjTypeSpecFldInfo::GetPropertyId() const
{
    return (Js::PropertyId)m_data.propertyId;
}

uint16
JITObjTypeSpecFldInfo::GetSlotIndex() const
{
    return m_data.slotIndex;
}

uint16
JITObjTypeSpecFldInfo::GetFixedFieldCount() const
{
    return m_data.fixedFieldCount;
}

uint
JITObjTypeSpecFldInfo::GetObjTypeSpecFldId() const
{
    return m_data.id;
}

intptr_t
JITObjTypeSpecFldInfo::GetProtoObject() const
{
    return m_data.protoObjectAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValue(uint i) const
{
    Assert(IsPoly());
    return m_data.fixedFieldInfoArray[i].fieldValue;
}

intptr_t
JITObjTypeSpecFldInfo::GetPropertyGuardValueAddr() const
{
    return m_data.propertyGuardValueAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
{
    Assert(HasFixedValue() && GetFixedFieldCount() == 1);

    return m_data.fixedFieldInfoArray[0].fieldValue;
}

JITTimeConstructorCache *
JITObjTypeSpecFldInfo::GetCtorCache() const
{
    return (JITTimeConstructorCache*)m_data.ctorCache;
}

Js::EquivalentTypeSet *
JITObjTypeSpecFldInfo::GetEquivalentTypeSet() const
{
    return (Js::EquivalentTypeSet *)m_data.typeSet;
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType() const
{
    Assert(IsMono());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[0].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType(uint i) const
{
    Assert(IsPoly());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[i].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetInitialType() const
{
    return JITTypeHolder((JITType *)m_data.initialType);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetFirstEquivalentType() const
{
    Assert(HasEquivalentTypeSet());
    return JITTypeHolder(GetEquivalentTypeSet()->GetFirstType());
}

void
JITObjTypeSpecFldInfo::SetIsBeingStored(bool value)
{
    ((Js::ObjTypeSpecFldInfoFlags*)&m_data.flags)->isBeingStored = value;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction()
{
    Assert(HasFixedValue());
    Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
    Assert(m_data.fixedFieldInfoArray);
    if (m_data.fixedFieldInfoArray[0].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[0];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction(uint i)
{
    Assert(HasFixedValue());
    Assert(IsPoly());
    if (m_data.fixedFieldCount > 0 && m_data.fixedFieldInfoArray[i].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[i];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldInfoArray()
{
    return (JITTimeFixedField*)m_data.fixedFieldInfoArray;
}

/* static */
void
JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(
    __in ArenaAllocator * alloc,
    __in Js::ObjTypeSpecFldInfo ** objTypeSpecInfo,
    __in uint arrayLength,
    _Inout_updates_(arrayLength) ObjTypeSpecFldIDL * jitData)
{
    for (uint i = 0; i < arrayLength; ++i)
    {
        if (objTypeSpecInfo[i] == nullptr)
        {
            continue;
        }
        jitData[i].inUse = TRUE;
        if (objTypeSpecInfo[i]->IsLoadedFromProto())
        {
            jitData[i].protoObjectAddr = (intptr_t)objTypeSpecInfo[i]->GetProtoObject();
        }
        jitData[i].propertyGuardValueAddr = (intptr_t)objTypeSpecInfo[i]->GetPropertyGuard()->GetAddressOfValue();
        jitData[i].propertyId = objTypeSpecInfo[i]->GetPropertyId();
        jitData[i].typeId = objTypeSpecInfo[i]->GetTypeId();
        jitData[i].id = objTypeSpecInfo[i]->GetObjTypeSpecFldId();
        jitData[i].flags = objTypeSpecInfo[i]->GetFlags();
        jitData[i].slotIndex = objTypeSpecInfo[i]->GetSlotIndex();
        jitData[i].fixedFieldCount = objTypeSpecInfo[i]->GetFixedFieldCount();

        if (objTypeSpecInfo[i]->HasInitialType())
        {
            jitData[i].initialType = AnewStructZ(alloc, TypeIDL);
            JITType::BuildFromJsType(objTypeSpecInfo[i]->GetInitialType(), (JITType*)jitData[i].initialType);
        }

        if (objTypeSpecInfo[i]->GetCtorCache() != nullptr)
        {
            jitData[i].ctorCache = objTypeSpecInfo[i]->GetCtorCache()->GetData();
        }

        CompileAssert(sizeof(Js::EquivalentTypeSet) == sizeof(EquivalentTypeSetIDL));
        Js::EquivalentTypeSet * equivTypeSet = objTypeSpecInfo[i]->GetEquivalentTypeSet();
        if (equivTypeSet != nullptr)
        {
            jitData[i].typeSet = (EquivalentTypeSetIDL*)equivTypeSet;
        }

        jitData[i].fixedFieldInfoArraySize = jitData[i].fixedFieldCount;
        if (jitData[i].fixedFieldInfoArraySize == 0)
        {
            jitData[i].fixedFieldInfoArraySize = 1;
        }
        jitData[i].fixedFieldInfoArray = AnewArrayZ(alloc, FixedFieldIDL, jitData[i].fixedFieldInfoArraySize);
        Js::FixedFieldInfo * ffInfo = objTypeSpecInfo[i]->GetFixedFieldInfoArray();
        for (uint16 j = 0; j < jitData[i].fixedFieldInfoArraySize; ++j)
        {
            jitData[i].fixedFieldInfoArray[j].fieldValue = (intptr_t)ffInfo[j].fieldValue;
            jitData[i].fixedFieldInfoArray[j].nextHasSameFixedField = ffInfo[j].nextHasSameFixedField;
            if (ffInfo[j].fieldValue != nullptr && Js::JavascriptFunction::Is(ffInfo[j].fieldValue))
            {
                Js::JavascriptFunction * funcObj = Js::JavascriptFunction::FromVar(ffInfo[j].fieldValue);
                jitData[i].fixedFieldInfoArray[j].valueType = ValueType::FromObject(funcObj).GetRawData();
                jitData[i].fixedFieldInfoArray[j].funcInfoAddr = (intptr_t)funcObj->GetFunctionInfo();
                jitData[i].fixedFieldInfoArray[j].isClassCtor = funcObj->GetFunctionInfo()->IsClassConstructor();
                jitData[i].fixedFieldInfoArray[j].localFuncId = (intptr_t)funcObj->GetFunctionInfo()->GetLocalFunctionId();
                if (Js::ScriptFunction::Is(ffInfo[j].fieldValue))
                {
                    jitData[i].fixedFieldInfoArray[j].environmentAddr = (intptr_t)Js::ScriptFunction::FromVar(funcObj)->GetEnvironment();
                }
            }
            if (ffInfo[j].type != nullptr)
            {
                jitData[i].fixedFieldInfoArray[j].type = AnewStructZ(alloc, TypeIDL);
                // TODO: OOP JIT, maybe type should be out of line? might not save anything on x64 though
                JITType::BuildFromJsType(ffInfo[j].type, (JITType*)jitData[i].fixedFieldInfoArray[j].type);
            }
        }
    }
}

Js::ObjTypeSpecFldInfoFlags
JITObjTypeSpecFldInfo::GetFlags() const
{
    return (Js::ObjTypeSpecFldInfoFlags)m_data.flags;
}
<|endoftext|>


<commit_before>//===-- Intercept.cpp - System function interception routines -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// If a function call occurs to an external function, the JIT is designed to use
// the dynamic loader interface to find a function to call.  This is useful for
// calling system calls and library functions that are not available in LLVM.
// Some system calls, however, need to be handled specially.  For this reason,
// we intercept some of them here and use our own stubs to handle them.
//
//===----------------------------------------------------------------------===//

#include "JIT.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Config/config.h"
using namespace llvm;

// AtExitHandlers - List of functions to call when the program exits,
// registered with the atexit() library function.
static std::vector<void (*)()> AtExitHandlers;

/// runAtExitHandlers - Run any functions registered by the program's
/// calls to atexit(3), which we intercept and store in
/// AtExitHandlers.
///
static void runAtExitHandlers() {
  while (!AtExitHandlers.empty()) {
    void (*Fn)() = AtExitHandlers.back();
    AtExitHandlers.pop_back();
    Fn();
  }
}

//===----------------------------------------------------------------------===//
// Function stubs that are invoked instead of certain library calls
//===----------------------------------------------------------------------===//

// Force the following functions to be linked in to anything that uses the
// JIT. This is a hack designed to work around the all-too-clever Glibc
// strategy of making these functions work differently when inlined vs. when
// not inlined, and hiding their real definitions in a separate archive file
// that the dynamic linker can't see. For more info, search for
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
#if defined(__linux__)
#if defined(HAVE_SYS_STAT_H)
#include <sys/stat.h>
#endif
void *FunctionPointers[] = {
  (void *)(intptr_t) stat,
  (void *)(intptr_t) fstat,
  (void *)(intptr_t) lstat,
  (void *)(intptr_t) stat64,
  (void *)(intptr_t) fstat64,
  (void *)(intptr_t) lstat64,
  (void *)(intptr_t) atexit,
  (void *)(intptr_t) mknod
};
#endif // __linux__

// jit_exit - Used to intercept the "exit" library call.
static void jit_exit(int Status) {
  runAtExitHandlers();   // Run atexit handlers...
  exit(Status);
}

// jit_atexit - Used to intercept the "atexit" library call.
static int jit_atexit(void (*Fn)(void)) {
  AtExitHandlers.push_back(Fn);    // Take note of atexit handler...
  return 0;  // Always successful
}

//===----------------------------------------------------------------------===//
//
/// getPointerToNamedFunction - This method returns the address of the specified
/// function by using the dynamic loader interface.  As such it is only useful
/// for resolving library symbols, not code generated symbols.
///
void *JIT::getPointerToNamedFunction(const std::string &Name) {
  // Check to see if this is one of the functions we want to intercept.  Note,
  // we cast to intptr_t here to silence a -pedantic warning that complains
  // about casting a function pointer to a normal pointer.
  if (Name == "exit") return (void*)(intptr_t)&jit_exit;
  if (Name == "atexit") return (void*)(intptr_t)&jit_atexit;

  const char *NameStr = Name.c_str();
  // If this is an asm specifier, skip the sentinal.
  if (NameStr[0] == 1) ++NameStr;

  // If it's an external function, look it up in the process image...
  void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
  if (Ptr) return Ptr;

  // If it wasn't found and if it starts with an underscore ('_') character, and
  // has an asm specifier, try again without the underscore.
  if (Name[0] == 1 && NameStr[0] == '_') {
    Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
    if (Ptr) return Ptr;
  }

  // darwin/ppc adds $LDBLStub suffixes to various symbols like printf.  These
  // are references to hidden visibility symbols that dlsym cannot resolve.  If
  // we have one of these, strip off $LDBLStub and try again.
#if defined(__APPLE__) && defined(__ppc__)
  if (Name.size() > 9 && Name[Name.size()-9] == '$' &&
      memcmp(&Name[Name.size()-8], "LDBLStub", 8) == 0)
    return getPointerToNamedFunction(std::string(Name.begin(),
                                                 Name.end()-9));
#endif

  /// If a LazyFunctionCreator is installed, use it to get/create the function.
  if (LazyFunctionCreator)
    if (void *RP = LazyFunctionCreator(Name))
      return RP;

  cerr << "ERROR: Program used external function '" << Name
       << "' which could not be resolved!\n";
  abort();
  return 0;
}
<commit_msg>Make this actually work on systems that support ppc long double.<commit_after>//===-- Intercept.cpp - System function interception routines -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// If a function call occurs to an external function, the JIT is designed to use
// the dynamic loader interface to find a function to call.  This is useful for
// calling system calls and library functions that are not available in LLVM.
// Some system calls, however, need to be handled specially.  For this reason,
// we intercept some of them here and use our own stubs to handle them.
//
//===----------------------------------------------------------------------===//

#include "JIT.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Config/config.h"
using namespace llvm;

// AtExitHandlers - List of functions to call when the program exits,
// registered with the atexit() library function.
static std::vector<void (*)()> AtExitHandlers;

/// runAtExitHandlers - Run any functions registered by the program's
/// calls to atexit(3), which we intercept and store in
/// AtExitHandlers.
///
static void runAtExitHandlers() {
  while (!AtExitHandlers.empty()) {
    void (*Fn)() = AtExitHandlers.back();
    AtExitHandlers.pop_back();
    Fn();
  }
}

//===----------------------------------------------------------------------===//
// Function stubs that are invoked instead of certain library calls
//===----------------------------------------------------------------------===//

// Force the following functions to be linked in to anything that uses the
// JIT. This is a hack designed to work around the all-too-clever Glibc
// strategy of making these functions work differently when inlined vs. when
// not inlined, and hiding their real definitions in a separate archive file
// that the dynamic linker can't see. For more info, search for
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
#if defined(__linux__)
#if defined(HAVE_SYS_STAT_H)
#include <sys/stat.h>
#endif
void *FunctionPointers[] = {
  (void *)(intptr_t) stat,
  (void *)(intptr_t) fstat,
  (void *)(intptr_t) lstat,
  (void *)(intptr_t) stat64,
  (void *)(intptr_t) fstat64,
  (void *)(intptr_t) lstat64,
  (void *)(intptr_t) atexit,
  (void *)(intptr_t) mknod
};
#endif // __linux__

// jit_exit - Used to intercept the "exit" library call.
static void jit_exit(int Status) {
  runAtExitHandlers();   // Run atexit handlers...
  exit(Status);
}

// jit_atexit - Used to intercept the "atexit" library call.
static int jit_atexit(void (*Fn)(void)) {
  AtExitHandlers.push_back(Fn);    // Take note of atexit handler...
  return 0;  // Always successful
}

//===----------------------------------------------------------------------===//
//
/// getPointerToNamedFunction - This method returns the address of the specified
/// function by using the dynamic loader interface.  As such it is only useful
/// for resolving library symbols, not code generated symbols.
///
void *JIT::getPointerToNamedFunction(const std::string &Name) {
  // Check to see if this is one of the functions we want to intercept.  Note,
  // we cast to intptr_t here to silence a -pedantic warning that complains
  // about casting a function pointer to a normal pointer.
  if (Name == "exit") return (void*)(intptr_t)&jit_exit;
  if (Name == "atexit") return (void*)(intptr_t)&jit_atexit;

  const char *NameStr = Name.c_str();
  // If this is an asm specifier, skip the sentinal.
  if (NameStr[0] == 1) ++NameStr;

  // If it's an external function, look it up in the process image...
  void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
  if (Ptr) return Ptr;

  // If it wasn't found and if it starts with an underscore ('_') character, and
  // has an asm specifier, try again without the underscore.
  if (Name[0] == 1 && NameStr[0] == '_') {
    Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
    if (Ptr) return Ptr;
  }

  // darwin/ppc adds $LDBLStub suffixes to various symbols like printf.  These
  // are references to hidden visibility symbols that dlsym cannot resolve.  If
  // we have one of these, strip off $LDBLStub and try again.
#if defined(__APPLE__) && defined(__ppc__)
  if (Name.size() > 9 && Name[Name.size()-9] == '$' &&
      memcmp(&Name[Name.size()-8], "LDBLStub", 8) == 0) {
    // First try turning $LDBLStub into $LDBL128.  If that fails, strip it off.
    // This mirrors logic in libSystemStubs.a.
    std::string Prefix = std::string(Name.begin(), Name.end()-9);
    if (void *Ptr = getPointerToNamedFunction(Prefix+"$LDBL128"))
      return Ptr;
    return getPointerToNamedFunction(Prefix);
  }
#endif

  /// If a LazyFunctionCreator is installed, use it to get/create the function.
  if (LazyFunctionCreator)
    if (void *RP = LazyFunctionCreator(Name))
      return RP;

  cerr << "ERROR: Program used external function '" << Name
       << "' which could not be resolved!\n";
  abort();
  return 0;
}
<|endoftext|>


<commit_before>/**
 * \file TypedBaseFilter.hxx
 */

#include <ATK/Core/TypedBaseFilter.h>
#include <ATK/Core/Utilities.h>

#include <complex>
#include <cstdint>
#include <iostream>
#include <type_traits>

#include <boost/mpl/contains.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>

#if USE_SIMD
#include <simdpp/simd.h>
#endif

namespace
{
  typedef boost::mpl::vector<std::int16_t, std::int32_t, int64_t, float, double, std::complex<float>, std::complex<double> > ConversionTypes;

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::mpl::empty<Vector>::type, void>::type
    convert_scalar_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    throw std::runtime_error("Cannot convert types for these filters");
  }

  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::is_arithmetic<typename boost::mpl::front<Vector>::type>::type, typename boost::disable_if<typename boost::mpl::empty<Vector>::type, void>::type>::type
  convert_scalar_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    convert_scalar_array<typename boost::mpl::pop_front<Vector>::type, DataType>(filter, port, converted_input, size, type - 1);
  }

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::is_arithmetic<typename boost::mpl::front<Vector>::type>::type, typename boost::disable_if<typename boost::mpl::empty<Vector>::type, void>::type>::type
    convert_scalar_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    if(type != 0)
    {
      convert_scalar_array<typename boost::mpl::pop_front<Vector>::type, DataType>(filter, port, converted_input, size, type - 1);
    }
    else
    {
      typedef typename boost::mpl::front<Vector>::type InputOriginalType;
      InputOriginalType* original_input_array = static_cast<ATK::TypedBaseFilter<InputOriginalType>*>(filter)->get_output_array(port);
      ATK::ConversionUtilities<InputOriginalType, DataType>::convert_array(original_input_array, converted_input, size);
    }
  }

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::mpl::empty<Vector>::type, void>::type
    convert_complex_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    throw std::runtime_error("Can't convert types");
  }

  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::mpl::empty<Vector>::type, void>::type
    convert_complex_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    assert(type >= 0);
    if (type != 0)
    {
      convert_complex_array<typename boost::mpl::pop_front<Vector>::type, DataType>(filter, port, converted_input, size, type - 1);
    }
    else
    {
      typedef typename boost::mpl::front<Vector>::type InputOriginalType;
      InputOriginalType* original_input_array = static_cast<ATK::TypedBaseFilter<InputOriginalType>*>(filter)->get_output_array(port);
      ATK::ConversionUtilities<InputOriginalType, DataType>::convert_array(original_input_array, converted_input, size);
    }
  }

  /// Conversion function for arithmetic types
  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::is_arithmetic<DataType>::type, void>::type convert_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    convert_scalar_array<Vector, DataType>(filter, port, converted_input, size, type);
  }

  /// Conversion function for other types not contained in ConversionTypes (no conversion in that case, just copy)
  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::is_arithmetic<DataType>::type, typename boost::disable_if<typename boost::mpl::contains<Vector, DataType>::type, void>::type>::type convert_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    assert(dynamic_cast<ATK::OutputArrayInterface<DataType>*>(filter));
     // For SIMD, you shouldn't call this, but adapt input/output delays so that there is no copy from one filter to another.
    DataType* original_input_array = dynamic_cast<ATK::TypedBaseFilter<DataType>*>(filter)->get_output_array(port);
    ATK::ConversionUtilities<DataType, DataType>::convert_array(original_input_array, converted_input, size);
  }

  /// Conversion function for std::complex contained in ConversionTypes
  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::is_arithmetic<DataType>::type, typename boost::enable_if<typename boost::mpl::contains<Vector, DataType>::type, void>::type>::type convert_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    convert_complex_array<Vector, DataType>(filter, port, converted_input, size, type);
  }

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::mpl::contains<Vector, DataType>::type, int>::type get_type()
  {
    return boost::mpl::distance<boost::mpl::begin<ConversionTypes>::type, typename boost::mpl::find<ConversionTypes, DataType>::type >::value;
  }

  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::mpl::contains<Vector, DataType>::type, int>::type get_type()
  {
    return -1;
  }
}

namespace ATK
{
  template<typename DataType>
  OutputArrayInterface<DataType>::~OutputArrayInterface()
  {
  }

  template<typename DataType_, typename DataType__>
  TypedBaseFilter<DataType_, DataType__>::TypedBaseFilter(std::size_t nb_input_ports, std::size_t nb_output_ports)
  :Parent(nb_input_ports, nb_output_ports), converted_inputs_delay(nb_input_ports), converted_inputs(nb_input_ports, nullptr), converted_inputs_size(nb_input_ports, 0), converted_in_delays(nb_input_ports, 0), direct_filters(nb_input_ports, nullptr), outputs_delay(nb_output_ports), outputs(nb_output_ports, nullptr), outputs_size(nb_output_ports, 0), out_delays(nb_output_ports, 0), default_input(nb_input_ports, TypeTraits<DataType_>::Zero()), default_output(nb_output_ports, TypeTraits<DataType__>::Zero())
  {
  }

  template<typename DataType_, typename DataType__>
  TypedBaseFilter<DataType_, DataType__>::TypedBaseFilter(TypedBaseFilter&& other)
  : Parent(std::move(other)), converted_inputs_delay(std::move(other.converted_inputs_delay)), converted_inputs(std::move(other.converted_inputs)), converted_inputs_size(std::move(other.converted_inputs_size)), converted_in_delays(std::move(other.converted_in_delays)), direct_filters(std::move(other.direct_filters)), outputs_delay(std::move(other.outputs_delay)), outputs(std::move(other.outputs)), outputs_size(std::move(other.outputs_size)), default_input(std::move(other.default_input)), default_output(std::move(other.default_output))
  {
  }

  template<typename DataType_, typename DataType__>
  TypedBaseFilter<DataType_, DataType__>::~TypedBaseFilter()
  {
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::set_nb_input_ports(std::size_t nb_ports)
  {
    if(nb_ports == nb_input_ports)
      return;
    Parent::set_nb_input_ports(nb_ports);
    converted_inputs_delay = std::vector<AlignedVector>(nb_ports);
    converted_inputs.assign(nb_ports, nullptr);
    converted_inputs_size.assign(nb_ports, 0);
    converted_in_delays.assign(nb_ports, 0);
    direct_filters.assign(nb_ports, nullptr);
    default_input.assign(nb_ports, TypeTraits<DataTypeInput>::Zero());
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::set_nb_output_ports(std::size_t nb_ports)
  {
    if(nb_ports == nb_output_ports)
      return;
    Parent::set_nb_output_ports(nb_ports);
    outputs_delay = std::vector<AlignedOutVector>(nb_ports);
    outputs.assign(nb_ports, nullptr);
    outputs_size.assign(nb_ports, 0);
    out_delays.assign(nb_ports, 0);
    default_output.assign(nb_ports, TypeTraits<DataTypeOutput>::Zero());
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::process_impl(std::size_t size) const
  {
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::prepare_process(std::size_t size)
  {
    convert_inputs(size);
  }

  template<typename DataType_, typename DataType__>
  int TypedBaseFilter<DataType_, DataType__>::get_type() const
  {
    return ::get_type<ConversionTypes, DataType__>();
  }

  template<typename DataType_, typename DataType__>
  DataType__* TypedBaseFilter<DataType_, DataType__>::get_output_array(std::size_t port) const
  {
    return outputs[port];
  }

  template<typename DataType_, typename DataType__>
  std::size_t TypedBaseFilter<DataType_, DataType__>::get_output_array_size() const
  {
    return outputs_size.front();
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::convert_inputs(std::size_t size)
  {
    for(unsigned int i = 0; i < nb_input_ports; ++i)
    {
      // if the input delay is smaller than the preceding filter output delay, we may have overlap
      // if the types are identical and if the type is not -1 (an unknown type)
      // if we have overlap, don't copy anything at all
      if((input_delay <= connections[i].second->get_output_delay()) && (direct_filters[i] != nullptr))
      {
        converted_inputs[i] = direct_filters[i]->get_output_array(connections[i].first);
        converted_inputs_size[i] = size;
        converted_in_delays[i] = input_delay;
        continue;
      }
      auto input_size = converted_inputs_size[i];
      auto in_delay = converted_in_delays[i];
      if(input_size < size || in_delay < input_delay)
      {
        // TODO Properly align the beginning of the data, not depending on input delay
        AlignedVector temp(input_delay + size, TypeTraits<DataTypeInput>::Zero());
        if(input_size == 0)
        {
          for(unsigned int j = 0; j < input_delay; ++j)
          {
            temp[j] = default_input[i];
          }
        }
        else
        {
          const auto input_ptr = converted_inputs[i];
          for(int j = 0; j < static_cast<int>(input_delay); ++j)
          {
            temp[j] = input_ptr[last_size + j - input_delay];
          }
        }

        converted_inputs_delay[i] = std::move(temp);
        converted_inputs[i] = converted_inputs_delay[i].data() + input_delay;
        converted_inputs_size[i] = size;
        converted_in_delays[i] = input_delay;
      }
      else
      {
        auto my_last_size = static_cast<int64_t>(last_size) * input_sampling_rate / output_sampling_rate;
        const auto input_ptr = converted_inputs[i];
        for(int j = 0; j < static_cast<int>(input_delay); ++j)
        {
          input_ptr[j - input_delay] = input_ptr[my_last_size + j - input_delay];
        }
      }
      convert_array<ConversionTypes, DataTypeInput>(connections[i].second, connections[i].first, converted_inputs[i], size, connections[i].second->get_type());
    }
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::prepare_outputs(std::size_t size)
  {
    for(unsigned int i = 0; i < nb_output_ports; ++i)
    {
      auto output_size = outputs_size[i];
      auto out_delay = out_delays[i];
      if(output_size < size || out_delay < output_delay)
      {
        // TODO Properly align the beginning of the data, not depending on output delay
        AlignedOutVector temp(output_delay + size, TypeTraits<DataTypeOutput>::Zero());
        if(output_size == 0)
        {
          for(unsigned int j = 0; j < output_delay; ++j)
          {
            temp[j] = default_output[i];
          }
        }
        else
        {
          const auto output_ptr = outputs[i];
          for(int j = 0; j < static_cast<int>(output_delay); ++j)
          {
            temp[j] = output_ptr[last_size + j - output_delay];
          }
        }

        outputs_delay[i] = std::move(temp);
        outputs[i] = outputs_delay[i].data() + output_delay;
        outputs_size[i] = size;
      }
      else
      {
        const auto output_ptr = outputs[i];
        for(int j = 0; j < static_cast<int>(output_delay); ++j)
        {
          output_ptr[j - output_delay] = output_ptr[last_size + j - output_delay];
        }
      }
    }
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::full_setup()
  {
    // Reset input arrays
    converted_inputs_delay = std::vector<AlignedVector>(nb_input_ports);
    converted_inputs.assign(nb_input_ports, nullptr);
    converted_inputs_size.assign(nb_input_ports, 0);
    converted_in_delays.assign(nb_input_ports, 0);

    // Reset output arrays
    outputs_delay = std::vector<AlignedOutVector>(nb_output_ports);
    outputs.assign(nb_output_ports, nullptr);
    outputs_size.assign(nb_output_ports, 0);
    out_delays.assign(nb_output_ports, 0);

    Parent::full_setup();
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::set_input_port(std::size_t input_port, BaseFilter* filter, std::size_t output_port)
  {
    Parent::set_input_port(input_port, filter, output_port);
    converted_inputs_size[input_port] = 0;
    converted_in_delays[input_port] = 0;
    direct_filters[input_port] = dynamic_cast<OutputArrayInterface<DataType_>*>(filter);
  }
}
<commit_msg>Fix temporary copy as well as output_delay save<commit_after>/**
 * \file TypedBaseFilter.hxx
 */

#include <ATK/Core/TypedBaseFilter.h>
#include <ATK/Core/Utilities.h>

#include <complex>
#include <cstdint>
#include <iostream>
#include <type_traits>

#include <boost/mpl/contains.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>

#if USE_SIMD
#include <simdpp/simd.h>
#endif

namespace
{
  typedef boost::mpl::vector<std::int16_t, std::int32_t, int64_t, float, double, std::complex<float>, std::complex<double> > ConversionTypes;

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::mpl::empty<Vector>::type, void>::type
    convert_scalar_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    throw std::runtime_error("Cannot convert types for these filters");
  }

  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::is_arithmetic<typename boost::mpl::front<Vector>::type>::type, typename boost::disable_if<typename boost::mpl::empty<Vector>::type, void>::type>::type
  convert_scalar_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    convert_scalar_array<typename boost::mpl::pop_front<Vector>::type, DataType>(filter, port, converted_input, size, type - 1);
  }

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::is_arithmetic<typename boost::mpl::front<Vector>::type>::type, typename boost::disable_if<typename boost::mpl::empty<Vector>::type, void>::type>::type
    convert_scalar_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    if(type != 0)
    {
      convert_scalar_array<typename boost::mpl::pop_front<Vector>::type, DataType>(filter, port, converted_input, size, type - 1);
    }
    else
    {
      typedef typename boost::mpl::front<Vector>::type InputOriginalType;
      InputOriginalType* original_input_array = static_cast<ATK::TypedBaseFilter<InputOriginalType>*>(filter)->get_output_array(port);
      ATK::ConversionUtilities<InputOriginalType, DataType>::convert_array(original_input_array, converted_input, size);
    }
  }

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::mpl::empty<Vector>::type, void>::type
    convert_complex_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    throw std::runtime_error("Can't convert types");
  }

  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::mpl::empty<Vector>::type, void>::type
    convert_complex_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    assert(type >= 0);
    if (type != 0)
    {
      convert_complex_array<typename boost::mpl::pop_front<Vector>::type, DataType>(filter, port, converted_input, size, type - 1);
    }
    else
    {
      typedef typename boost::mpl::front<Vector>::type InputOriginalType;
      InputOriginalType* original_input_array = static_cast<ATK::TypedBaseFilter<InputOriginalType>*>(filter)->get_output_array(port);
      ATK::ConversionUtilities<InputOriginalType, DataType>::convert_array(original_input_array, converted_input, size);
    }
  }

  /// Conversion function for arithmetic types
  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::is_arithmetic<DataType>::type, void>::type convert_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    convert_scalar_array<Vector, DataType>(filter, port, converted_input, size, type);
  }

  /// Conversion function for other types not contained in ConversionTypes (no conversion in that case, just copy)
  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::is_arithmetic<DataType>::type, typename boost::disable_if<typename boost::mpl::contains<Vector, DataType>::type, void>::type>::type convert_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    assert(dynamic_cast<ATK::OutputArrayInterface<DataType>*>(filter));
     // For SIMD, you shouldn't call this, but adapt input/output delays so that there is no copy from one filter to another.
    DataType* original_input_array = dynamic_cast<ATK::TypedBaseFilter<DataType>*>(filter)->get_output_array(port);
    ATK::ConversionUtilities<DataType, DataType>::convert_array(original_input_array, converted_input, size);
  }

  /// Conversion function for std::complex contained in ConversionTypes
  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::is_arithmetic<DataType>::type, typename boost::enable_if<typename boost::mpl::contains<Vector, DataType>::type, void>::type>::type convert_array(ATK::BaseFilter* filter, unsigned int port, DataType* converted_input, std::size_t size, int type)
  {
    convert_complex_array<Vector, DataType>(filter, port, converted_input, size, type);
  }

  template<typename Vector, typename DataType>
  typename boost::enable_if<typename boost::mpl::contains<Vector, DataType>::type, int>::type get_type()
  {
    return boost::mpl::distance<boost::mpl::begin<ConversionTypes>::type, typename boost::mpl::find<ConversionTypes, DataType>::type >::value;
  }

  template<typename Vector, typename DataType>
  typename boost::disable_if<typename boost::mpl::contains<Vector, DataType>::type, int>::type get_type()
  {
    return -1;
  }
}

namespace ATK
{
  template<typename DataType>
  OutputArrayInterface<DataType>::~OutputArrayInterface()
  {
  }

  template<typename DataType_, typename DataType__>
  TypedBaseFilter<DataType_, DataType__>::TypedBaseFilter(std::size_t nb_input_ports, std::size_t nb_output_ports)
  :Parent(nb_input_ports, nb_output_ports), converted_inputs_delay(nb_input_ports), converted_inputs(nb_input_ports, nullptr), converted_inputs_size(nb_input_ports, 0), converted_in_delays(nb_input_ports, 0), direct_filters(nb_input_ports, nullptr), outputs_delay(nb_output_ports), outputs(nb_output_ports, nullptr), outputs_size(nb_output_ports, 0), out_delays(nb_output_ports, 0), default_input(nb_input_ports, TypeTraits<DataType_>::Zero()), default_output(nb_output_ports, TypeTraits<DataType__>::Zero())
  {
  }

  template<typename DataType_, typename DataType__>
  TypedBaseFilter<DataType_, DataType__>::TypedBaseFilter(TypedBaseFilter&& other)
  : Parent(std::move(other)), converted_inputs_delay(std::move(other.converted_inputs_delay)), converted_inputs(std::move(other.converted_inputs)), converted_inputs_size(std::move(other.converted_inputs_size)), converted_in_delays(std::move(other.converted_in_delays)), direct_filters(std::move(other.direct_filters)), outputs_delay(std::move(other.outputs_delay)), outputs(std::move(other.outputs)), outputs_size(std::move(other.outputs_size)), default_input(std::move(other.default_input)), default_output(std::move(other.default_output))
  {
  }

  template<typename DataType_, typename DataType__>
  TypedBaseFilter<DataType_, DataType__>::~TypedBaseFilter()
  {
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::set_nb_input_ports(std::size_t nb_ports)
  {
    if(nb_ports == nb_input_ports)
      return;
    Parent::set_nb_input_ports(nb_ports);
    converted_inputs_delay = std::vector<AlignedVector>(nb_ports);
    converted_inputs.assign(nb_ports, nullptr);
    converted_inputs_size.assign(nb_ports, 0);
    converted_in_delays.assign(nb_ports, 0);
    direct_filters.assign(nb_ports, nullptr);
    default_input.assign(nb_ports, TypeTraits<DataTypeInput>::Zero());
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::set_nb_output_ports(std::size_t nb_ports)
  {
    if(nb_ports == nb_output_ports)
      return;
    Parent::set_nb_output_ports(nb_ports);
    outputs_delay = std::vector<AlignedOutVector>(nb_ports);
    outputs.assign(nb_ports, nullptr);
    outputs_size.assign(nb_ports, 0);
    out_delays.assign(nb_ports, 0);
    default_output.assign(nb_ports, TypeTraits<DataTypeOutput>::Zero());
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::process_impl(std::size_t size) const
  {
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::prepare_process(std::size_t size)
  {
    convert_inputs(size);
  }

  template<typename DataType_, typename DataType__>
  int TypedBaseFilter<DataType_, DataType__>::get_type() const
  {
    return ::get_type<ConversionTypes, DataType__>();
  }

  template<typename DataType_, typename DataType__>
  DataType__* TypedBaseFilter<DataType_, DataType__>::get_output_array(std::size_t port) const
  {
    return outputs[port];
  }

  template<typename DataType_, typename DataType__>
  std::size_t TypedBaseFilter<DataType_, DataType__>::get_output_array_size() const
  {
    return outputs_size.front();
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::convert_inputs(std::size_t size)
  {
    for(unsigned int i = 0; i < nb_input_ports; ++i)
    {
      // if the input delay is smaller than the preceding filter output delay, we may have overlap
      // if the types are identical and if the type is not -1 (an unknown type)
      // if we have overlap, don't copy anything at all
      if((input_delay <= connections[i].second->get_output_delay()) && (direct_filters[i] != nullptr))
      {
        converted_inputs[i] = direct_filters[i]->get_output_array(connections[i].first);
        converted_inputs_size[i] = size;
        converted_in_delays[i] = input_delay;
        continue;
      }
      auto input_size = converted_inputs_size[i];
      auto in_delay = converted_in_delays[i];
      if(input_size < size || in_delay < input_delay)
      {
        // TODO Properly align the beginning of the data, not depending on input delay
        AlignedVector temp(input_delay + size, TypeTraits<DataTypeInput>::Zero());
        if(input_size == 0)
        {
          for(unsigned int j = 0; j < input_delay; ++j)
          {
            temp[j] = default_input[i];
          }
        }
        else
        {
          const auto input_ptr = converted_inputs[i];
          for(int j = 0; j < static_cast<int>(in_delay); ++j)
          {
            temp[j] = input_ptr[last_size + j - in_delay];
          }
        }

        converted_inputs_delay[i] = std::move(temp);
        converted_inputs[i] = converted_inputs_delay[i].data() + input_delay;
        converted_inputs_size[i] = size;
        converted_in_delays[i] = input_delay;
      }
      else
      {
        auto my_last_size = static_cast<int64_t>(last_size) * input_sampling_rate / output_sampling_rate;
        const auto input_ptr = converted_inputs[i];
        for(int j = 0; j < static_cast<int>(input_delay); ++j)
        {
          input_ptr[j - input_delay] = input_ptr[my_last_size + j - input_delay];
        }
      }
      convert_array<ConversionTypes, DataTypeInput>(connections[i].second, connections[i].first, converted_inputs[i], size, connections[i].second->get_type());
    }
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::prepare_outputs(std::size_t size)
  {
    for(unsigned int i = 0; i < nb_output_ports; ++i)
    {
      auto output_size = outputs_size[i];
      auto out_delay = out_delays[i];
      if(output_size < size || out_delay < output_delay)
      {
        // TODO Properly align the beginning of the data, not depending on output delay
        AlignedOutVector temp(output_delay + size, TypeTraits<DataTypeOutput>::Zero());
        if(output_size == 0)
        {
          for(unsigned int j = 0; j < output_delay; ++j)
          {
            temp[j] = default_output[i];
          }
        }
        else
        {
          const auto output_ptr = outputs[i];
          for(int j = 0; j < static_cast<int>(out_delay); ++j)
          {
            temp[j] = output_ptr[last_size + j - out_delay];
          }
        }

        outputs_delay[i] = std::move(temp);
        outputs[i] = outputs_delay[i].data() + output_delay;
        outputs_size[i] = size;
        out_delays[i] = output_delay;
      }
      else
      {
        const auto output_ptr = outputs[i];
        for(int j = 0; j < static_cast<int>(output_delay); ++j)
        {
          output_ptr[j - output_delay] = output_ptr[last_size + j - output_delay];
        }
      }
    }
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::full_setup()
  {
    // Reset input arrays
    converted_inputs_delay = std::vector<AlignedVector>(nb_input_ports);
    converted_inputs.assign(nb_input_ports, nullptr);
    converted_inputs_size.assign(nb_input_ports, 0);
    converted_in_delays.assign(nb_input_ports, 0);

    // Reset output arrays
    outputs_delay = std::vector<AlignedOutVector>(nb_output_ports);
    outputs.assign(nb_output_ports, nullptr);
    outputs_size.assign(nb_output_ports, 0);
    out_delays.assign(nb_output_ports, 0);

    Parent::full_setup();
  }

  template<typename DataType_, typename DataType__>
  void TypedBaseFilter<DataType_, DataType__>::set_input_port(std::size_t input_port, BaseFilter* filter, std::size_t output_port)
  {
    Parent::set_input_port(input_port, filter, output_port);
    converted_inputs_size[input_port] = 0;
    converted_in_delays[input_port] = 0;
    direct_filters[input_port] = dynamic_cast<OutputArrayInterface<DataType_>*>(filter);
  }
}
<|endoftext|>


<commit_before>#include "game.hpp"

#define SCORE_MAX 3

// helper functions

static void
draw();

static void
resetBall();

// game state functions

static void
menuTitle();

static void
gameSetup();

static void
gameMain();

static void
menuWin();

static void
menuLose();

void (*gameTick)(){ &menuTitle };
Ball ball;
Player player;
Computer computer;

void
draw()
{
	// cool border around the screen
	arduboy.drawRect(0, 0, WIDTH, HEIGHT, WHITE);
	// dotted line in the middle
	for (uint8_t i{ 2 }; i < HEIGHT; i += 8)
	{
		arduboy.drawFastVLine(WIDTH / 2, i, 4, WHITE);
	}
	// scores
	arduboy.setCursor(WIDTH/2 - 12, 2);
	arduboy.print(player.score);
	arduboy.setCursor(WIDTH/2 + 3, 2);
	arduboy.print(computer.score);
	// objects
	ball.draw();
	player.draw();
	computer.draw();
}

void
resetBall()
{
	ball.x = WIDTH / 2;
	ball.y = HEIGHT / 2;
	ball.dx = 1;
	ball.dy = 1;
}

void
menuTitle()
{
	arduboy.setCursor(0, 0);
	arduboy.print(F("Press A to\nstart"));
	if (arduboy.pressed(A_BUTTON))
	{
		gameTick = &gameSetup;
	}
}

void
gameSetup()
{
	arduboy.initRandomSeed();
	resetBall();
	player.x = 9;
	player.y = 24; // i thought of something funnier than 24...
	player.score = 0;
	computer.x = WIDTH - PADDLE_WIDTH - 9;
	computer.y = 25; // twenyfiiive!
	computer.score = 0;
	draw();
	arduboy.display();
	delay(1000);
	gameTick = &gameMain;
}

void
gameMain()
{
	draw();
	ball.move();
	// check if someone scored
	if (ball.x >= WIDTH - BALL_SIZE)
	{
		sound.tone(POINT_FREQ, POINT_DUR);
		if (++player.score >= SCORE_MAX)
		{
			gameTick = &menuWin;
			return;
		}
		else
		{
			resetBall();
		}
	}
	else if (ball.x < 1)
	{
		sound.tone(POINT_FREQ, POINT_DUR);
		if (++computer.score >= SCORE_MAX)
		{
			gameTick = &menuLose;
			return;
		}
		else
		{
			resetBall();
		}
	}
	ball.bounce();
	player.move();
	computer.move();
}

void
menuWin()
{
	arduboy.setCursor(0, 0);
	arduboy.print(F("You win!\nPress A to\nrestart"));
	if (arduboy.pressed(A_BUTTON))
	{
		gameTick = &gameSetup;
	}
}

void
menuLose()
{
	arduboy.setCursor(0, 0);
	arduboy.print(F("You lost!\nPress A to\nrestart"));
	if (arduboy.pressed(A_BUTTON))
	{
		gameTick = &gameSetup;
	}
}
<commit_msg>Add pause state<commit_after>#include "game.hpp"

#define SCORE_MAX 3

// helper functions

static void
draw();

static void
resetBall();

// game state functions

static void
menuTitle();

static void
gameSetup();

static void
gameMain();

static void
gamePause();

static void
menuWin();

static void
menuLose();

void (*gameTick)(){ &menuTitle };
Ball ball;
Player player;
Computer computer;

void
draw()
{
	// cool border around the screen
	arduboy.drawRect(0, 0, WIDTH, HEIGHT, WHITE);
	// dotted line in the middle
	for (uint8_t i{ 2 }; i < HEIGHT; i += 8)
	{
		arduboy.drawFastVLine(WIDTH / 2, i, 4, WHITE);
	}
	// scores
	arduboy.setCursor(WIDTH/2 - 12, 2);
	arduboy.print(player.score);
	arduboy.setCursor(WIDTH/2 + 3, 2);
	arduboy.print(computer.score);
	// objects
	ball.draw();
	player.draw();
	computer.draw();
}

void
resetBall()
{
	ball.x = WIDTH / 2;
	ball.y = HEIGHT / 2;
	ball.dx = 1;
	ball.dy = 1;
}

void
menuTitle()
{
	arduboy.setCursor(0, 0);
	arduboy.print(F("Press A to\nstart"));
	if (arduboy.pressed(A_BUTTON))
	{
		gameTick = &gameSetup;
	}
}

void
gameSetup()
{
	arduboy.initRandomSeed();
	resetBall();
	player.x = 9;
	player.y = 24; // i thought of something funnier than 24...
	player.score = 0;
	computer.x = WIDTH - PADDLE_WIDTH - 9;
	computer.y = 25; // twenyfiiive!
	computer.score = 0;
	draw();
	arduboy.display();
	delay(1000);
	gameTick = &gameMain;
}

void
gameMain()
{
	draw();
	// pause the game if needed
	if (arduboy.justPressed(A_BUTTON))
	{
		gameTick = &gamePause;
		return;
	}
	ball.move();
	// check if someone scored
	if (ball.x >= WIDTH - BALL_SIZE)
	{
		sound.tone(POINT_FREQ, POINT_DUR);
		if (++player.score >= SCORE_MAX)
		{
			gameTick = &menuWin;
			return;
		}
		else
		{
			resetBall();
		}
	}
	else if (ball.x < 1)
	{
		sound.tone(POINT_FREQ, POINT_DUR);
		if (++computer.score >= SCORE_MAX)
		{
			gameTick = &menuLose;
			return;
		}
		else
		{
			resetBall();
		}
	}
	ball.bounce();
	player.move();
	computer.move();
}

void
gamePause()
{
	draw();
	// resume the game if needed
	if (arduboy.justPressed(A_BUTTON))
	{
		gameTick = &gameMain;
	}
}

void
menuWin()
{
	arduboy.setCursor(0, 0);
	arduboy.print(F("You win!\nPress A to\nrestart"));
	if (arduboy.pressed(A_BUTTON))
	{
		gameTick = &gameSetup;
	}
}

void
menuLose()
{
	arduboy.setCursor(0, 0);
	arduboy.print(F("You lost!\nPress A to\nrestart"));
	if (arduboy.pressed(A_BUTTON))
	{
		gameTick = &gameSetup;
	}
}
<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>

#include "util/coordinate_calculation.hpp"

#include <osrm/coordinate.hpp>

#include <cmath>

using namespace osrm;
using namespace osrm::util;

// Regression test for bug captured in #1347
BOOST_AUTO_TEST_CASE(regression_test_1347)
{
    Coordinate u(FloatLongitude(-100), FloatLatitude(10));
    Coordinate v(FloatLongitude(-100.002), FloatLatitude(10.001));
    Coordinate q(FloatLongitude(-100.001), FloatLatitude(10.002));

    double d1 = coordinate_calculation::perpendicularDistance(u, v, q);

    double ratio;
    Coordinate nearest_location;
    double d2 = coordinate_calculation::perpendicularDistance(u, v, q, nearest_location, ratio);

    BOOST_CHECK_LE(std::abs(d1 - d2), 0.01);
}
<commit_msg>Add tests for coordinate transformation<commit_after>#include <boost/test/unit_test.hpp>

#include "util/coordinate_calculation.hpp"

#include <osrm/coordinate.hpp>

#include <cmath>

using namespace osrm;
using namespace osrm::util;

// Regression test for bug captured in #1347
BOOST_AUTO_TEST_CASE(regression_test_1347)
{
    Coordinate u(FloatLongitude(-100), FloatLatitude(10));
    Coordinate v(FloatLongitude(-100.002), FloatLatitude(10.001));
    Coordinate q(FloatLongitude(-100.001), FloatLatitude(10.002));

    double d1 = coordinate_calculation::perpendicularDistance(u, v, q);

    double ratio;
    Coordinate nearest_location;
    double d2 = coordinate_calculation::perpendicularDistance(u, v, q, nearest_location, ratio);

    BOOST_CHECK_LE(std::abs(d1 - d2), 0.01);
}

BOOST_AUTO_TEST_CASE(lon_to_pixel)
{
    using namespace coordinate_calculation;
    BOOST_CHECK_CLOSE(7.416042 * mercator::DEGREE_TO_PX, 825550.019142, 0.1);
    BOOST_CHECK_CLOSE(7.415892 * mercator::DEGREE_TO_PX, 825533.321218, 0.1);
    BOOST_CHECK_CLOSE(7.416016 * mercator::DEGREE_TO_PX, 825547.124835, 0.1);
    BOOST_CHECK_CLOSE(7.41577 * mercator::DEGREE_TO_PX, 825519.74024, 0.1);
    BOOST_CHECK_CLOSE(7.415808 * mercator::DEGREE_TO_PX, 825523.970381, 0.1);
}

BOOST_AUTO_TEST_CASE(lat_to_pixel)
{
    using namespace coordinate_calculation;
    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733947)) * mercator::DEGREE_TO_PX,
                      5424361.75863, 0.1);
    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733799)) * mercator::DEGREE_TO_PX,
                      5424338.95731, 0.1);
    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733922)) * mercator::DEGREE_TO_PX,
                      5424357.90705, 0.1);
    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733697)) * mercator::DEGREE_TO_PX,
                      5424323.24293, 0.1);
    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733729)) * mercator::DEGREE_TO_PX,
                      5424328.17293, 0.1);
}

BOOST_AUTO_TEST_CASE(xyz_to_wgs84)
{
    using namespace coordinate_calculation;

    double minx_1;
    double miny_1;
    double maxx_1;
    double maxy_1;
    mercator::xyzToWSG84(2, 2, 1, minx_1, miny_1, maxx_1, maxy_1);
    BOOST_CHECK_CLOSE(minx_1, 180, 0.0001);
    BOOST_CHECK_CLOSE(miny_1, -89.786, 0.0001);
    BOOST_CHECK_CLOSE(maxx_1, 360, 0.0001);
    BOOST_CHECK_CLOSE(maxy_1, -85.0511, 0.0001);

    double minx_2;
    double miny_2;
    double maxx_2;
    double maxy_2;
    mercator::xyzToWSG84(100, 0, 13, minx_2, miny_2, maxx_2, maxy_2);
    BOOST_CHECK_CLOSE(minx_2, -175.6054, 0.0001);
    BOOST_CHECK_CLOSE(miny_2, 85.0473, 0.0001);
    BOOST_CHECK_CLOSE(maxx_2, -175.5615, 0.0001);
    BOOST_CHECK_CLOSE(maxy_2, 85.0511, 0.0001);
}

BOOST_AUTO_TEST_CASE(xyz_to_mercator)
{
    using namespace coordinate_calculation;

    double minx;
    double miny;
    double maxx;
    double maxy;
    mercator::xyzToMercator(100, 0, 13, minx, miny, maxx, maxy);

    BOOST_CHECK_CLOSE(minx, -19548311.361764118075, 0.0001);
    BOOST_CHECK_CLOSE(miny, 20032616.372979003936, 0.0001);
    BOOST_CHECK_CLOSE(maxx, -19543419.391953866929, 0.0001);
    BOOST_CHECK_CLOSE(maxy, 20037508.342789277434, 0.0001);
}
<|endoftext|>


<commit_before>/*********************************************************************
 * NAN - Native Abstractions for Node.js
 *
 * Copyright (c) 2018 NAN contributors
 *
 * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
 ********************************************************************/

#include <nan.h>

#include <stdint.h>

using namespace Nan;  // NOLINT(build/namespaces)

NAN_METHOD(ReadU8) {
  TypedArrayContents<uint8_t> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());
  for (size_t i=0; i<data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_METHOD(ReadI32) {
  TypedArrayContents<int32_t> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());
  for (size_t i=0; i<data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_METHOD(ReadFloat) {
  TypedArrayContents<float> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());\
  for (size_t i=0; i<data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_METHOD(ReadDouble) {
  TypedArrayContents<double> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());
  for (size_t i=0; i<data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_MODULE_INIT(Init) {
  NAN_EXPORT(target, ReadU8);
  NAN_EXPORT(target, ReadI32);
  NAN_EXPORT(target, ReadFloat);
  NAN_EXPORT(target, ReadDouble);
}

NODE_MODULE(typedarrays, Init)
<commit_msg>typedarrays.cpp: Missing spaces around <  [whitespace/operators] [3]<commit_after>/*********************************************************************
 * NAN - Native Abstractions for Node.js
 *
 * Copyright (c) 2018 NAN contributors
 *
 * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
 ********************************************************************/

#include <nan.h>

#include <stdint.h>

using namespace Nan;  // NOLINT(build/namespaces)

NAN_METHOD(ReadU8) {
  TypedArrayContents<uint8_t> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());
  for (size_t i=0; i < data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_METHOD(ReadI32) {
  TypedArrayContents<int32_t> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());
  for (size_t i=0; i < data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_METHOD(ReadFloat) {
  TypedArrayContents<float> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());\
  for (size_t i=0; i < data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_METHOD(ReadDouble) {
  TypedArrayContents<double> data(info[0]);

  v8::Local<v8::Array> result = New<v8::Array>(data.length());
  for (size_t i=0; i < data.length(); i++) {
    Set(result, i, New<v8::Number>((*data)[i]));
  }

  info.GetReturnValue().Set(result);
}

NAN_MODULE_INIT(Init) {
  NAN_EXPORT(target, ReadU8);
  NAN_EXPORT(target, ReadI32);
  NAN_EXPORT(target, ReadFloat);
  NAN_EXPORT(target, ReadDouble);
}

NODE_MODULE(typedarrays, Init)
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <accessibility/standard/vclxaccessibletabpagewindow.hxx>
#include <toolkit/helper/convert.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabpage.hxx>

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::accessibility;
using namespace ::comphelper;

//  ----------------------------------------------------
//  class VCLXAccessibleTabPageWindow
//  ----------------------------------------------------

VCLXAccessibleTabPageWindow::VCLXAccessibleTabPageWindow( VCLXWindow* pVCLXWindow )
    :VCLXAccessibleComponent( pVCLXWindow )
{
    m_pTabPage = static_cast< TabPage* >( GetWindow() );
    m_pTabControl = 0;
    m_nPageId = 0;
    if ( m_pTabPage )
    {
        Window* pParent = m_pTabPage->GetAccessibleParentWindow();
        if ( pParent && pParent->GetType() == WINDOW_TABCONTROL )
        {
            m_pTabControl = static_cast< TabControl* >( pParent );
            if ( m_pTabControl )
            {
                for ( sal_uInt16 i = 0, nCount = m_pTabControl->GetPageCount(); i < nCount; ++i )
                {
                    sal_uInt16 nPageId = m_pTabControl->GetPageId( i );
                    if ( m_pTabControl->GetTabPage( nPageId ) == m_pTabPage )
                        m_nPageId = nPageId;
                }
            }
        }
    }
}

// -----------------------------------------------------------------------------

VCLXAccessibleTabPageWindow::~VCLXAccessibleTabPageWindow()
{
}

// -----------------------------------------------------------------------------
// OCommonAccessibleComponent
// -----------------------------------------------------------------------------

awt::Rectangle VCLXAccessibleTabPageWindow::implGetBounds() throw (RuntimeException)
{
    awt::Rectangle aBounds( 0, 0, 0, 0 );

    if ( m_pTabControl )
    {
        Rectangle aPageRect = m_pTabControl->GetTabBounds( m_nPageId );
        if ( m_pTabPage )
        {
            Rectangle aRect = Rectangle( m_pTabPage->GetPosPixel(), m_pTabPage->GetSizePixel() );
            aRect.Move( -aPageRect.Left(), -aPageRect.Top() );
            aBounds = AWTRectangle( aRect );
        }
    }

    return aBounds;
}

// -----------------------------------------------------------------------------
// XComponent
// -----------------------------------------------------------------------------

void VCLXAccessibleTabPageWindow::disposing()
{
    VCLXAccessibleComponent::disposing();

    m_pTabControl = NULL;
    m_pTabPage = NULL;
}

// -----------------------------------------------------------------------------
// XAccessibleContext
// -----------------------------------------------------------------------------

Reference< XAccessible > VCLXAccessibleTabPageWindow::getAccessibleParent(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    Reference< XAccessible > xParent;
    if ( m_pTabControl )
    {
        Reference< XAccessible > xAcc( m_pTabControl->GetAccessible() );
        if ( xAcc.is() )
        {
            Reference< XAccessibleContext > xCont( xAcc->getAccessibleContext() );
            if ( xCont.is() )
                xParent = xCont->getAccessibleChild( m_pTabControl->GetPagePos( m_nPageId ) );
        }
    }

    return xParent;
}

// -----------------------------------------------------------------------------

sal_Int32 VCLXAccessibleTabPageWindow::getAccessibleIndexInParent(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    return 0;
}

// -----------------------------------------------------------------------------

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>VCLXAccessibleTabPageWindow: unhandled IndexOutOfBoundsException<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <accessibility/standard/vclxaccessibletabpagewindow.hxx>
#include <toolkit/helper/convert.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabpage.hxx>

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::accessibility;
using namespace ::comphelper;

//  ----------------------------------------------------
//  class VCLXAccessibleTabPageWindow
//  ----------------------------------------------------

VCLXAccessibleTabPageWindow::VCLXAccessibleTabPageWindow( VCLXWindow* pVCLXWindow )
    :VCLXAccessibleComponent( pVCLXWindow )
{
    m_pTabPage = static_cast< TabPage* >( GetWindow() );
    m_pTabControl = 0;
    m_nPageId = 0;
    if ( m_pTabPage )
    {
        Window* pParent = m_pTabPage->GetAccessibleParentWindow();
        if ( pParent && pParent->GetType() == WINDOW_TABCONTROL )
        {
            m_pTabControl = static_cast< TabControl* >( pParent );
            if ( m_pTabControl )
            {
                for ( sal_uInt16 i = 0, nCount = m_pTabControl->GetPageCount(); i < nCount; ++i )
                {
                    sal_uInt16 nPageId = m_pTabControl->GetPageId( i );
                    if ( m_pTabControl->GetTabPage( nPageId ) == m_pTabPage )
                        m_nPageId = nPageId;
                }
            }
        }
    }
}

// -----------------------------------------------------------------------------

VCLXAccessibleTabPageWindow::~VCLXAccessibleTabPageWindow()
{
}

// -----------------------------------------------------------------------------
// OCommonAccessibleComponent
// -----------------------------------------------------------------------------

awt::Rectangle VCLXAccessibleTabPageWindow::implGetBounds() throw (RuntimeException)
{
    awt::Rectangle aBounds( 0, 0, 0, 0 );

    if ( m_pTabControl )
    {
        Rectangle aPageRect = m_pTabControl->GetTabBounds( m_nPageId );
        if ( m_pTabPage )
        {
            Rectangle aRect = Rectangle( m_pTabPage->GetPosPixel(), m_pTabPage->GetSizePixel() );
            aRect.Move( -aPageRect.Left(), -aPageRect.Top() );
            aBounds = AWTRectangle( aRect );
        }
    }

    return aBounds;
}

// -----------------------------------------------------------------------------
// XComponent
// -----------------------------------------------------------------------------

void VCLXAccessibleTabPageWindow::disposing()
{
    VCLXAccessibleComponent::disposing();

    m_pTabControl = NULL;
    m_pTabPage = NULL;
}

// -----------------------------------------------------------------------------
// XAccessibleContext
// -----------------------------------------------------------------------------

Reference< XAccessible > VCLXAccessibleTabPageWindow::getAccessibleParent(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    Reference< XAccessible > xParent;
    if ( m_pTabControl )
    {
        Reference< XAccessible > xAcc( m_pTabControl->GetAccessible() );
        if ( xAcc.is() )
        {
            Reference< XAccessibleContext > xCont( xAcc->getAccessibleContext() );
            if ( xCont.is() )
            {
                sal_uInt16 const nPagePos(m_pTabControl->GetPagePos(m_nPageId));
                SAL_WARN_IF(TAB_PAGE_NOTFOUND == nPagePos, "accessibility",
                        "getAccessibleParent(): no tab page");
                if (TAB_PAGE_NOTFOUND != nPagePos)
                {
                    xParent = xCont->getAccessibleChild(nPagePos);
                }
            }
        }
    }

    return xParent;
}

// -----------------------------------------------------------------------------

sal_Int32 VCLXAccessibleTabPageWindow::getAccessibleIndexInParent(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    return 0;
}

// -----------------------------------------------------------------------------

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


<commit_before>#ifndef LOCK_FREE_QUEUE_HPP
#define LOCK_FREE_QUEUE_HPP

#include <atomic>
#include <utility>

namespace ctl {
    /// Thread safe and lock free FIFO queue.
    /** Note: implementation is from:
        http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448
    **/
    template<typename T>
    class lock_free_queue {
        struct node {
            node() : next(nullptr) {}
            template<typename U>
            node(U&& t) : data(std::forward<U>(t)), next(nullptr) {}

            T     data;
            node* next;
        };

        node* first_;
        std::atomic<node*> dummy_, last_;

    public :
        lock_free_queue() {
            // Always keep a dummy separator between head and tail
            first_ = last_ = dummy_ = new node();
        }

        ~lock_free_queue() {
            // Clear the whole queue
            while (first_ != nullptr) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }
        }

        lock_free_queue(const lock_free_queue& q) = delete;
        lock_free_queue& operator = (const lock_free_queue& q) = delete;

        /// Push a new element at the back of the queue.
        /** Called by the 'producer' thread only.
        **/
        template<typename U>
        void push(U&& t) {
            // Add the new item to the queue
            (*last_).next = new node(std::forward<U>(t));
            last_ = (*last_).next;

            // Clear consumed items
            while (first_ != dummy_) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }
        }

        /// Pop an element from the front of the queue.
        /** Called by the 'consumer' thread only.
        **/
        bool pop(T& t) {
            // Return false if queue is empty
            if (dummy_!= last_) {
                // Consume the value
                t = std::move((*dummy_).next->data);
                dummy_ = (*dummy_).next;
                return true;
            } else {
                return false;
            }
        }

        /// Check if this queue is empty.
        /** Called by the 'consumer' thread only.
        **/
        bool empty() const {
            return dummy_ == last_;
        }

        /// Delete all elements from the queue.
        /** This method should not be used in concurrent situations
        **/
        void clear() {
            while (first_ != dummy_) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }

            first_ = dummy_.load();

            while (first_->next != nullptr) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }

            last_ = dummy_ = first_;
        }
    };
}

#endif
<commit_msg>Added lock_free_queue::size().<commit_after>#ifndef LOCK_FREE_QUEUE_HPP
#define LOCK_FREE_QUEUE_HPP

#include <atomic>
#include <utility>

namespace ctl {
    /// Thread safe and lock free FIFO queue.
    /** Note: implementation is from:
        http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448
    **/
    template<typename T>
    class lock_free_queue {
        struct node {
            node() : next(nullptr) {}
            template<typename U>
            node(U&& t) : data(std::forward<U>(t)), next(nullptr) {}

            T     data;
            node* next;
        };

        // Modified and read by 'procuder' only
        node* first_;
        // Modified and read by 'consumer', read by 'producer'
        std::atomic<node*> dummy_;
        // Modified and read by 'procuder', read by 'consumer'
        std::atomic<node*> last_;

    public :
        lock_free_queue() {
            // Always keep a dummy separator between head and tail
            first_ = last_ = dummy_ = new node();
        }

        ~lock_free_queue() {
            // Clear the whole queue
            while (first_ != nullptr) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }
        }

        lock_free_queue(const lock_free_queue& q) = delete;
        lock_free_queue& operator = (const lock_free_queue& q) = delete;

        /// Push a new element at the back of the queue.
        /** Called by the 'producer' thread only.
        **/
        template<typename U>
        void push(U&& t) {
            // Add the new item to the queue
            (*last_).next = new node(std::forward<U>(t));
            last_ = (*last_).next;

            // Clear consumed items
            while (first_ != dummy_) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }
        }

        /// Pop an element from the front of the queue.
        /** Called by the 'consumer' thread only.
        **/
        bool pop(T& t) {
            // Return false if queue is empty
            if (dummy_ != last_) {
                // Consume the value
                t = std::move((*dummy_).next->data);
                dummy_ = (*dummy_).next;
                return true;
            } else {
                return false;
            }
        }

        /// Compute the current number of elements in the queue.
        /** Called by the 'consumer' thread only.
            Note that the true size may actually be larger than the returned value if the
            'producer' thread pushes new elements while the size is computed.
        **/
        std::size_t size() const {
            node* tmp = dummy_.load();
            node* end = last_.load();
            std::size_t n = 0;

            while (tmp != end) {
                tmp = tmp->next;
                ++n;
            }

            return n;
        }

        /// Check if this queue is empty.
        /** Called by the 'consumer' thread only.
        **/
        bool empty() const {
            return dummy_ == last_;
        }

        /// Delete all elements from the queue.
        /** This method should not be used in concurrent situations
        **/
        void clear() {
            while (first_ != dummy_) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }

            first_ = dummy_.load();

            while (first_->next != nullptr) {
                node* temp = first_;
                first_ = temp->next;
                delete temp;
            }

            last_ = dummy_ = first_;
        }
    };
}

#endif
<|endoftext|>


<commit_before>/*
 * Android File Transfer for Linux: MTP client for android devices
 * Copyright (C) 2015  Vladimir Menshakov

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include <usb/Device.h>
#include <usb/Exception.h>
#include <mtp/usb/TimeoutException.h>
#include <mtp/ByteArray.h>

#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <sys/time.h>

#include "linux/usbdevice_fs.h"

#define IOCTL(...) do { int r = ioctl(__VA_ARGS__); if (r < 0) throw Exception("ioctl(" #__VA_ARGS__ ")"); } while(false)

namespace mtp { namespace usb
{
	Device::InterfaceToken::InterfaceToken(int fd, unsigned interfaceNumber): _fd(fd), _interfaceNumber(interfaceNumber)
	{
		IOCTL(_fd, USBDEVFS_CLAIMINTERFACE, &interfaceNumber);
	}

	Device::InterfaceToken::~InterfaceToken()
	{
		ioctl(_fd, USBDEVFS_RELEASEINTERFACE, &_interfaceNumber);
	}

	Device::Device(int fd): _fd(fd)
	{
		IOCTL(_fd, USBDEVFS_GET_CAPABILITIES, &_capabilities);
	}

	Device::~Device()
	{
		close(_fd);
	}

	int Device::GetConfiguration() const
	{
		return 0;
	}

	void Device::SetConfiguration(int idx)
	{
		fprintf(stderr, "SetConfiguration(%d): not implemented", idx);
	}

	void * Device::Reap(int timeout)
	{
		timeval started = {};
		if (gettimeofday(&started, NULL) == -1)
			throw usb::Exception("gettimeofday");
		pollfd fd = {};
		fd.fd		= _fd;
		fd.events	= POLLOUT;
		int r = poll(&fd, 1, timeout);

		timeval now = {};
		if (gettimeofday(&now, NULL) == -1)
			throw usb::Exception("gettimeofday");

		if (r < 0)
			throw Exception("poll");
		if (r == 0)
		{
			int ms = (now.tv_sec - started.tv_sec) * 1000 + (now.tv_usec - started.tv_usec) / 1000;
			fprintf(stderr, "%d ms since the last poll call\n", ms);
			throw TimeoutException("timeout reaping usb urb");
		}

		usbdevfs_urb *urb;
		r = ioctl(_fd, USBDEVFS_REAPURBNDELAY, &urb);
		if (r == 0)
			return urb;
		else
			throw Exception("ioctl");
	}

	void Device::ReapSingleUrb(void *urb, int timeout)
	{
		void * reapUrb = Reap(timeout);
		if (urb != reapUrb)
		{
			fprintf(stderr, "reaping unknown urb, usb bus conflict: %p %p\n", urb, reapUrb);
			std::terminate();
		}
	}

	void Device::WriteBulk(const EndpointPtr & ep, const IObjectInputStreamPtr &inputStream, int timeout)
	{
		size_t transferSize = ep->GetMaxPacketSize() * 1024;
		ByteArray data(transferSize);

		size_t r;
		bool continuation = false;
		do
		{
			r = inputStream->Read(data.data(), data.size());
			//HexDump("write", ByteArray(data.data(), data.data() + r));
			usbdevfs_urb urb = {};
			urb.type = USBDEVFS_URB_TYPE_BULK;
			urb.endpoint = ep->GetAddress();
			urb.buffer = const_cast<u8 *>(data.data());
			urb.buffer_length = r;
			if (continuation)
				urb.flags |= USBDEVFS_URB_BULK_CONTINUATION;
			else
				continuation = true;
			IOCTL(_fd, USBDEVFS_SUBMITURB, &urb);
			try
			{
				ReapSingleUrb(&urb, timeout);
			}
			catch(const std::exception &ex)
			{
				int r = ioctl(_fd, USBDEVFS_DISCARDURB, &urb);
				if (r != 0)
					std::terminate();
				fprintf(stderr, "exception %s: discard = %d\n", ex.what(), r);
				throw;
			}
		}
		while(r == transferSize);
	}

	void Device::ReadBulk(const EndpointPtr & ep, const IObjectOutputStreamPtr &outputStream, int timeout)
	{
		ByteArray data(ep->GetMaxPacketSize() * 1024);
		usbdevfs_urb urb = {};
		bool continuation = false;
		do
		{
			urb.type = USBDEVFS_URB_TYPE_BULK;
			urb.endpoint = ep->GetAddress();
			urb.buffer = data.data();
			urb.buffer_length = data.size();
			if (continuation)
				urb.flags |= USBDEVFS_URB_BULK_CONTINUATION;
			else
				continuation = true;
			IOCTL(_fd, USBDEVFS_SUBMITURB, &urb);

			try
			{
				ReapSingleUrb(&urb, timeout);
			}
			catch(const std::exception &ex)
			{
				int r = ioctl(_fd, USBDEVFS_DISCARDURB, &urb);
				if (r != 0)
					std::terminate();
				fprintf(stderr, "exception %s: discard = %d\n", ex.what(), r);
				throw;
			}
			//HexDump("read", ByteArray(data.data(), data.data() + urb.actual_length));
			outputStream->Write(data.data(), urb.actual_length);
		}
		while(urb.actual_length == (int)data.size());
	}

}}<commit_msg>lock device file descriptor to avoid conflicts<commit_after>/*
 * Android File Transfer for Linux: MTP client for android devices
 * Copyright (C) 2015  Vladimir Menshakov

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include <usb/Device.h>
#include <usb/Exception.h>
#include <mtp/usb/TimeoutException.h>
#include <mtp/ByteArray.h>

#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <sys/time.h>

#include "linux/usbdevice_fs.h"

#define IOCTL(...) do { int r = ioctl(__VA_ARGS__); if (r < 0) throw Exception("ioctl(" #__VA_ARGS__ ")"); } while(false)

namespace mtp { namespace usb
{
	Device::InterfaceToken::InterfaceToken(int fd, unsigned interfaceNumber): _fd(fd), _interfaceNumber(interfaceNumber)
	{
		IOCTL(_fd, USBDEVFS_CLAIMINTERFACE, &interfaceNumber);
	}

	Device::InterfaceToken::~InterfaceToken()
	{
		ioctl(_fd, USBDEVFS_RELEASEINTERFACE, &_interfaceNumber);
	}

	Device::Device(int fd): _fd(fd)
	{
		IOCTL(_fd, USBDEVFS_GET_CAPABILITIES, &_capabilities);
		int r = lockf(_fd, F_TLOCK, 0);
		if (r == -1)
			throw Exception("device is used by another process");
	}

	Device::~Device()
	{
		lockf(_fd, F_ULOCK, 0);
		close(_fd);
	}

	int Device::GetConfiguration() const
	{
		return 0;
	}

	void Device::SetConfiguration(int idx)
	{
		fprintf(stderr, "SetConfiguration(%d): not implemented", idx);
	}

	void * Device::Reap(int timeout)
	{
		timeval started = {};
		if (gettimeofday(&started, NULL) == -1)
			throw usb::Exception("gettimeofday");
		pollfd fd = {};
		fd.fd		= _fd;
		fd.events	= POLLOUT;
		int r = poll(&fd, 1, timeout);

		timeval now = {};
		if (gettimeofday(&now, NULL) == -1)
			throw usb::Exception("gettimeofday");

		if (r < 0)
			throw Exception("poll");
		if (r == 0)
		{
			int ms = (now.tv_sec - started.tv_sec) * 1000 + (now.tv_usec - started.tv_usec) / 1000;
			fprintf(stderr, "%d ms since the last poll call\n", ms);
			throw TimeoutException("timeout reaping usb urb");
		}

		usbdevfs_urb *urb;
		r = ioctl(_fd, USBDEVFS_REAPURBNDELAY, &urb);
		if (r == 0)
			return urb;
		else
			throw Exception("ioctl");
	}

	void Device::ReapSingleUrb(void *urb, int timeout)
	{
		void * reapUrb = Reap(timeout);
		if (urb != reapUrb)
		{
			fprintf(stderr, "reaping unknown urb, usb bus conflict: %p %p\n", urb, reapUrb);
			std::terminate();
		}
	}

	void Device::WriteBulk(const EndpointPtr & ep, const IObjectInputStreamPtr &inputStream, int timeout)
	{
		size_t transferSize = ep->GetMaxPacketSize() * 1024;
		ByteArray data(transferSize);

		size_t r;
		bool continuation = false;
		do
		{
			r = inputStream->Read(data.data(), data.size());
			//HexDump("write", ByteArray(data.data(), data.data() + r));
			usbdevfs_urb urb = {};
			urb.type = USBDEVFS_URB_TYPE_BULK;
			urb.endpoint = ep->GetAddress();
			urb.buffer = const_cast<u8 *>(data.data());
			urb.buffer_length = r;
			if (continuation)
				urb.flags |= USBDEVFS_URB_BULK_CONTINUATION;
			else
				continuation = true;
			IOCTL(_fd, USBDEVFS_SUBMITURB, &urb);
			try
			{
				ReapSingleUrb(&urb, timeout);
			}
			catch(const std::exception &ex)
			{
				int r = ioctl(_fd, USBDEVFS_DISCARDURB, &urb);
				if (r != 0)
					std::terminate();
				fprintf(stderr, "exception %s: discard = %d\n", ex.what(), r);
				throw;
			}
		}
		while(r == transferSize);
	}

	void Device::ReadBulk(const EndpointPtr & ep, const IObjectOutputStreamPtr &outputStream, int timeout)
	{
		ByteArray data(ep->GetMaxPacketSize() * 1024);
		usbdevfs_urb urb = {};
		bool continuation = false;
		do
		{
			urb.type = USBDEVFS_URB_TYPE_BULK;
			urb.endpoint = ep->GetAddress();
			urb.buffer = data.data();
			urb.buffer_length = data.size();
			if (continuation)
				urb.flags |= USBDEVFS_URB_BULK_CONTINUATION;
			else
				continuation = true;
			IOCTL(_fd, USBDEVFS_SUBMITURB, &urb);

			try
			{
				ReapSingleUrb(&urb, timeout);
			}
			catch(const std::exception &ex)
			{
				int r = ioctl(_fd, USBDEVFS_DISCARDURB, &urb);
				if (r != 0)
					std::terminate();
				fprintf(stderr, "exception %s: discard = %d\n", ex.what(), r);
				throw;
			}
			//HexDump("read", ByteArray(data.data(), data.data() + urb.actual_length));
			outputStream->Write(data.data(), urb.actual_length);
		}
		while(urb.actual_length == (int)data.size());
	}

}}<|endoftext|>