<commit_before>//===--- AccessSummaryAnalysis.cpp - SIL Access Summary Analysis ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-access-summary-analysis"
#include "swift/SIL/SILArgument.h"
#include "swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h"
#include "swift/SILOptimizer/Analysis/FunctionOrder.h"
#include "swift/SILOptimizer/PassManager/PassManager.h"

using namespace swift;

void AccessSummaryAnalysis::processFunction(FunctionInfo *info,
                                            FunctionOrder &order) {
  // Does the summary need to be recomputed?
  if (order.prepareForVisiting(info))
    return;

  // Compute function summary on a per-argument basis.
  unsigned index = 0;
  for (SILArgument *arg : info->getFunction()->getArguments()) {
    FunctionSummary &functionSummary = info->getSummary();
    ArgumentSummary &argSummary =
        functionSummary.getAccessForArgument(index);
    index++;

    auto *functionArg = cast<SILFunctionArgument>(arg);
    // Only summarize @inout_aliasable arguments.
    SILArgumentConvention convention =
        functionArg->getArgumentConvention().Value;
    if (convention != SILArgumentConvention::Indirect_InoutAliasable)
      continue;

    processArgument(info, functionArg, argSummary, order);
  }
}

/// Track uses of the arguments, recording in the summary any accesses
/// started by a begin_access and any flows of the arguments to other
/// functions.
void AccessSummaryAnalysis::processArgument(FunctionInfo *info,
                                             SILFunctionArgument *argument,
                                             ArgumentSummary &summary,
                                             FunctionOrder &order) {
  unsigned argumentIndex = argument->getIndex();

  // Use a worklist to track argument uses to be processed.
  llvm::SmallVector<Operand *, 32> worklist;

  // Start by adding the immediate uses of the argument to the worklist.
  worklist.append(argument->use_begin(), argument->use_end());

  // Iterate to follow uses of the arguments.
  while (!worklist.empty()) {
    Operand *operand = worklist.pop_back_val();
    SILInstruction *user = operand->getUser();

    switch (user->getKind()) {
    case ValueKind::BeginAccessInst: {
      auto *BAI = cast<BeginAccessInst>(user);
      summary.mergeWith(BAI->getAccessKind(), BAI->getLoc());
      // We don't add the users of the begin_access to the worklist because
      // even if these users eventually begin an access to the address
      // or a projection from it, that access can't begin more exclusive
      // access than this access -- otherwise it will be diagnosed
      // elsewhere.
      break;
    }
    case ValueKind::EndUnpairedAccessInst:
      // Don't diagnose unpaired access statically.
      assert(cast<EndUnpairedAccessInst>(user)->getEnforcement() ==
             SILAccessEnforcement::Dynamic);
      break;
    case ValueKind::StructElementAddrInst:
    case ValueKind::TupleElementAddrInst:
      // Eventually we'll summarize individual struct elements separately.
      // For now an access to a part of the struct is treated as an access
      // to the whole struct.
      worklist.append(user->use_begin(), user->use_end());
      break;
    case ValueKind::DebugValueAddrInst:
    case ValueKind::AddressToPointerInst:
      // Ignore these uses, they don't affect formal accesses.
      break;
    case ValueKind::PartialApplyInst:
      processPartialApply(info, argumentIndex, cast<PartialApplyInst>(user),
                          operand, order);
      break;
    case ValueKind::ApplyInst:
      processFullApply(info, argumentIndex, cast<ApplyInst>(user), operand,
                       order);
      break;
    case ValueKind::TryApplyInst:
      processFullApply(info, argumentIndex, cast<TryApplyInst>(user), operand,
                       order);
      break;
    case ValueKind::CopyAddrInst:
    case ValueKind::ExistentialMetatypeInst:
    case ValueKind::ValueMetatypeInst:
    case ValueKind::LoadInst:
    case ValueKind::LoadBorrowInst:
    case ValueKind::EndBorrowInst:
    case ValueKind::OpenExistentialAddrInst:
    case ValueKind::ProjectBlockStorageInst:
      // These likely represent scenarios in which we're not generating
      // begin access markers. Ignore these for now. But we really should
      // add SIL verification to ensure all loads and stores have associated
      // access markers.
      break;
    default:
      // TODO: These requirements should be checked for in the SIL verifier.
      // This is an assertion rather than llvm_unreachable() because
      // it is likely the whitelist above for scenarios in which we'ren
      // not generating access markers is not comprehensive.
      assert(false && "Unrecognized argument use");
      break;
    }
  }
}

#ifndef NDEBUG
/// Sanity check to make sure that a noescape partial apply is
/// only ultimately used by an apply, a try_apply or as an argument (but not
/// the called function) in a partial_apply.
/// TODO: This really should be checked in the SILVerifier.
static bool hasExpectedUsesOfNoEscapePartialApply(Operand *partialApplyUse) {
  SILInstruction *user = partialApplyUse->getUser();

  // It is fine to call the partial apply
  switch (user->getKind()) {
  case ValueKind::ApplyInst:
  case ValueKind::TryApplyInst:
    return true;

  case ValueKind::ConvertFunctionInst:
    return llvm::all_of(user->getUses(),
                        hasExpectedUsesOfNoEscapePartialApply);

  case ValueKind::PartialApplyInst:
    return partialApplyUse->get() != cast<PartialApplyInst>(user)->getCallee();

  case ValueKind::StoreInst:
  case ValueKind::DestroyValueInst:
    // @block_storage is passed by storing it to the stack. We know this is
    // still nonescaping simply because our original argument convention is
    // @inout_aliasable. In this SIL, both store and destroy_value are users
    // of %closure:
    //
    // %closure = partial_apply %f1(%arg)
    //   : $@convention(thin) (@inout_aliasable T) -> ()
    // %storage = alloc_stack $@block_storage @callee_owned () -> ()
    // %block_addr = project_block_storage %storage
    //   : $*@block_storage @callee_owned () -> ()
    // store %closure to [init] %block_addr : $*@callee_owned () -> ()
    // %block = init_block_storage_header %storage
    //     : $*@block_storage @callee_owned () -> (),
    //   invoke %f2 : $@convention(c)
    //     (@inout_aliasable @block_storage @callee_owned () -> ()) -> (),
    //   type $@convention(block) () -> ()
    // %copy = copy_block %block : $@convention(block) () -> ()
    // destroy_value %storage : $@callee_owned () -> ()
    return true;
  default:
    return false;
  }
}
#endif

void AccessSummaryAnalysis::processPartialApply(FunctionInfo *callerInfo,
                                                unsigned callerArgumentIndex,
                                                PartialApplyInst *apply,
                                                Operand *applyArgumentOperand,
                                                FunctionOrder &order) {
  SILFunction *calleeFunction = apply->getCalleeFunction();
  assert(calleeFunction && !calleeFunction->empty() &&
         "Missing definition of noescape closure?");

  // Make sure the partial_apply is not calling the result of another
  // partial_apply.
  assert(isa<FunctionRefInst>(apply->getCallee()) &&
         "Noescape partial apply of non-functionref?");

  assert(llvm::all_of(apply->getUses(),
                      hasExpectedUsesOfNoEscapePartialApply) &&
         "noescape partial_apply has unexpected use!");

  // The argument index in the called function.
  ApplySite site(apply);
  unsigned calleeArgumentIndex = site.getCalleeArgIndex(*applyArgumentOperand);

  processCall(callerInfo, callerArgumentIndex, calleeFunction,
              calleeArgumentIndex, order);
}

void AccessSummaryAnalysis::processFullApply(FunctionInfo *callerInfo,
                                             unsigned callerArgumentIndex,
                                             FullApplySite apply,
                                             Operand *argumentOperand,
                                             FunctionOrder &order) {
  unsigned operandNumber = argumentOperand->getOperandNumber();
  assert(operandNumber > 0 && "Summarizing apply for non-argument?");

  unsigned calleeArgumentIndex = operandNumber - 1;
  SILFunction *callee = apply.getCalleeFunction();
  // We can't apply a summary for function whose body we can't see.
  // Since user-provided closures are always in the same module as their callee
  // This likely indicates a missing begin_access before an open-coded
  // call.
  if (!callee || callee->empty())
    return;

  processCall(callerInfo, callerArgumentIndex, callee, calleeArgumentIndex,
              order);
}

void AccessSummaryAnalysis::processCall(FunctionInfo *callerInfo,
                                        unsigned callerArgumentIndex,
                                        SILFunction *callee,
                                        unsigned argumentIndex,
                                        FunctionOrder &order) {
  // Record the flow of an argument from  the caller to the callee so that
  // the interprocedural analysis can iterate to a fixpoint.
  FunctionInfo *calleeInfo = getFunctionInfo(callee);
  ArgumentFlow flow = {callerArgumentIndex, argumentIndex, calleeInfo};
  callerInfo->recordFlow(flow);
  if (!calleeInfo->isVisited()) {
    processFunction(calleeInfo, order);
    order.tryToSchedule(calleeInfo);
  }

  propagateFromCalleeToCaller(callerInfo, flow);
}

bool AccessSummaryAnalysis::ArgumentSummary::mergeWith(SILAccessKind otherKind,
                                                        SILLocation otherLoc) {
  // In the lattice, a modification-like accesses subsume a read access or no
  // access.
  if (!Kind.hasValue() ||
      (*Kind == SILAccessKind::Read && otherKind != SILAccessKind::Read)) {
    Kind = otherKind;
    AccessLoc = otherLoc;
    return true;
  }

  return false;
}

bool AccessSummaryAnalysis::ArgumentSummary::mergeWith(
    const ArgumentSummary &other) {
  if (other.Kind.hasValue())
    return mergeWith(*other.Kind, other.AccessLoc);
  return false;
}

void AccessSummaryAnalysis::recompute(FunctionInfo *initial) {
  allocNewUpdateID();

  FunctionOrder order(getCurrentUpdateID());

  // Summarize the function and its callees.
  processFunction(initial, order);

  // Build the bottom-up order.
  order.tryToSchedule(initial);
  order.finishScheduling();

  // Iterate the interprocedural analysis to a fixed point.
  bool needAnotherIteration;
  do {
    needAnotherIteration = false;
    for (FunctionInfo *calleeInfo : order) {
      for (const auto &callerEntry : calleeInfo->getCallers()) {
        assert(callerEntry.isValid());
        if (!order.wasRecomputedWithCurrentUpdateID(calleeInfo))
          continue;

        FunctionInfo *callerInfo = callerEntry.Caller;

        // Propagate from callee to caller.
        for (const auto &argumentFlow : callerInfo->getArgumentFlows()) {
          if (argumentFlow.CalleeFunctionInfo != calleeInfo)
            continue;

          bool changed = propagateFromCalleeToCaller(callerInfo, argumentFlow);
          if (changed && !callerInfo->isScheduledAfter(calleeInfo)) {
            needAnotherIteration = true;
          }
        }
      }
    }
  } while (needAnotherIteration);
}

StringRef AccessSummaryAnalysis::ArgumentSummary::getDescription() const {
  if (Optional<SILAccessKind> kind = getAccessKind()) {
    return getSILAccessKindName(*kind);
  }

  return "none";
}

bool AccessSummaryAnalysis::propagateFromCalleeToCaller(
    FunctionInfo *callerInfo, ArgumentFlow flow) {
  // For a given flow from a caller's argument to a callee's argument,
  // propagate the argument summary information to the caller.

  FunctionInfo *calleeInfo = flow.CalleeFunctionInfo;
  const auto &calleeArgument =
      calleeInfo->getSummary().getAccessForArgument(flow.CalleeArgumentIndex);
  auto &callerArgument =
      callerInfo->getSummary().getAccessForArgument(flow.CallerArgumentIndex);

  bool changed = callerArgument.mergeWith(calleeArgument);
  return changed;
}

AccessSummaryAnalysis::FunctionInfo *
AccessSummaryAnalysis::getFunctionInfo(SILFunction *F) {
  FunctionInfo *&FInfo = FunctionInfos[F];
  if (!FInfo) {
    FInfo = new (Allocator.Allocate()) FunctionInfo(F);
  }
  return FInfo;
}

const AccessSummaryAnalysis::FunctionSummary &
AccessSummaryAnalysis::getOrCreateSummary(SILFunction *fn) {
  FunctionInfo *info = getFunctionInfo(fn);
  if (!info->isValid())
    recompute(info);

  return info->getSummary();
}

void AccessSummaryAnalysis::AccessSummaryAnalysis::invalidate() {
  FunctionInfos.clear();
  Allocator.DestroyAll();
  delete SubPathTrie;
  SubPathTrie = new IndexTrieNode();
}

void AccessSummaryAnalysis::invalidate(SILFunction *F, InvalidationKind K) {
  FunctionInfos.erase(F);
}

SILAnalysis *swift::createAccessSummaryAnalysis(SILModule *M) {
  return new AccessSummaryAnalysis();
}

raw_ostream &swift::
operator<<(raw_ostream &os,
           const AccessSummaryAnalysis::FunctionSummary &summary) {
  unsigned argCount = summary.getArgumentCount();
  os << "(";

  if (argCount > 0) {
    os << summary.getAccessForArgument(0).getDescription();
    for (unsigned i = 1; i < argCount; i++) {
      os << ",  " << summary.getAccessForArgument(i).getDescription();
    }
  }

  os << ")";
  return os;
}
<commit_msg>Disable an unnecessary assert in AccessSummaryAnalysis.<commit_after>//===--- AccessSummaryAnalysis.cpp - SIL Access Summary Analysis ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-access-summary-analysis"
#include "swift/SIL/SILArgument.h"
#include "swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h"
#include "swift/SILOptimizer/Analysis/FunctionOrder.h"
#include "swift/SILOptimizer/PassManager/PassManager.h"

using namespace swift;

void AccessSummaryAnalysis::processFunction(FunctionInfo *info,
                                            FunctionOrder &order) {
  // Does the summary need to be recomputed?
  if (order.prepareForVisiting(info))
    return;

  // Compute function summary on a per-argument basis.
  unsigned index = 0;
  for (SILArgument *arg : info->getFunction()->getArguments()) {
    FunctionSummary &functionSummary = info->getSummary();
    ArgumentSummary &argSummary =
        functionSummary.getAccessForArgument(index);
    index++;

    auto *functionArg = cast<SILFunctionArgument>(arg);
    // Only summarize @inout_aliasable arguments.
    SILArgumentConvention convention =
        functionArg->getArgumentConvention().Value;
    if (convention != SILArgumentConvention::Indirect_InoutAliasable)
      continue;

    processArgument(info, functionArg, argSummary, order);
  }
}

/// Track uses of the arguments, recording in the summary any accesses
/// started by a begin_access and any flows of the arguments to other
/// functions.
void AccessSummaryAnalysis::processArgument(FunctionInfo *info,
                                             SILFunctionArgument *argument,
                                             ArgumentSummary &summary,
                                             FunctionOrder &order) {
  unsigned argumentIndex = argument->getIndex();

  // Use a worklist to track argument uses to be processed.
  llvm::SmallVector<Operand *, 32> worklist;

  // Start by adding the immediate uses of the argument to the worklist.
  worklist.append(argument->use_begin(), argument->use_end());

  // Iterate to follow uses of the arguments.
  while (!worklist.empty()) {
    Operand *operand = worklist.pop_back_val();
    SILInstruction *user = operand->getUser();

    switch (user->getKind()) {
    case ValueKind::BeginAccessInst: {
      auto *BAI = cast<BeginAccessInst>(user);
      summary.mergeWith(BAI->getAccessKind(), BAI->getLoc());
      // We don't add the users of the begin_access to the worklist because
      // even if these users eventually begin an access to the address
      // or a projection from it, that access can't begin more exclusive
      // access than this access -- otherwise it will be diagnosed
      // elsewhere.
      break;
    }
    case ValueKind::EndUnpairedAccessInst:
      // Don't diagnose unpaired access statically.
      assert(cast<EndUnpairedAccessInst>(user)->getEnforcement() ==
             SILAccessEnforcement::Dynamic);
      break;
    case ValueKind::StructElementAddrInst:
    case ValueKind::TupleElementAddrInst:
      // Eventually we'll summarize individual struct elements separately.
      // For now an access to a part of the struct is treated as an access
      // to the whole struct.
      worklist.append(user->use_begin(), user->use_end());
      break;
    case ValueKind::DebugValueAddrInst:
    case ValueKind::AddressToPointerInst:
      // Ignore these uses, they don't affect formal accesses.
      break;
    case ValueKind::PartialApplyInst:
      processPartialApply(info, argumentIndex, cast<PartialApplyInst>(user),
                          operand, order);
      break;
    case ValueKind::ApplyInst:
      processFullApply(info, argumentIndex, cast<ApplyInst>(user), operand,
                       order);
      break;
    case ValueKind::TryApplyInst:
      processFullApply(info, argumentIndex, cast<TryApplyInst>(user), operand,
                       order);
      break;
    default:
      // FIXME: These likely represent scenarios in which we're not generating
      // begin access markers. Ignore these for now. But we really should
      // add SIL verification to ensure all loads and stores have associated
      // access markers. Once SIL verification is implemented, enable the
      // following assert to verify that the whitelist above is comprehensive,
      // which guarnatees that exclusivity enforcement is complete.
      //   assert(false && "Unrecognized argument use");
      break;
    }
  }
}

#ifndef NDEBUG
/// Sanity check to make sure that a noescape partial apply is
/// only ultimately used by an apply, a try_apply or as an argument (but not
/// the called function) in a partial_apply.
///
/// FIXME: This needs to be checked in the SILVerifier.
static bool hasExpectedUsesOfNoEscapePartialApply(Operand *partialApplyUse) {
  SILInstruction *user = partialApplyUse->getUser();

  // It is fine to call the partial apply
  switch (user->getKind()) {
  case ValueKind::ApplyInst:
  case ValueKind::TryApplyInst:
    return true;

  case ValueKind::ConvertFunctionInst:
    return llvm::all_of(user->getUses(),
                        hasExpectedUsesOfNoEscapePartialApply);

  case ValueKind::PartialApplyInst:
    return partialApplyUse->get() != cast<PartialApplyInst>(user)->getCallee();

  case ValueKind::StoreInst:
  case ValueKind::DestroyValueInst:
    // @block_storage is passed by storing it to the stack. We know this is
    // still nonescaping simply because our original argument convention is
    // @inout_aliasable. In this SIL, both store and destroy_value are users
    // of %closure:
    //
    // %closure = partial_apply %f1(%arg)
    //   : $@convention(thin) (@inout_aliasable T) -> ()
    // %storage = alloc_stack $@block_storage @callee_owned () -> ()
    // %block_addr = project_block_storage %storage
    //   : $*@block_storage @callee_owned () -> ()
    // store %closure to [init] %block_addr : $*@callee_owned () -> ()
    // %block = init_block_storage_header %storage
    //     : $*@block_storage @callee_owned () -> (),
    //   invoke %f2 : $@convention(c)
    //     (@inout_aliasable @block_storage @callee_owned () -> ()) -> (),
    //   type $@convention(block) () -> ()
    // %copy = copy_block %block : $@convention(block) () -> ()
    // destroy_value %storage : $@callee_owned () -> ()
    return true;
  default:
    return false;
  }
}
#endif

void AccessSummaryAnalysis::processPartialApply(FunctionInfo *callerInfo,
                                                unsigned callerArgumentIndex,
                                                PartialApplyInst *apply,
                                                Operand *applyArgumentOperand,
                                                FunctionOrder &order) {
  SILFunction *calleeFunction = apply->getCalleeFunction();
  assert(calleeFunction && !calleeFunction->empty() &&
         "Missing definition of noescape closure?");

  // Make sure the partial_apply is not calling the result of another
  // partial_apply.
  assert(isa<FunctionRefInst>(apply->getCallee()) &&
         "Noescape partial apply of non-functionref?");

  assert(llvm::all_of(apply->getUses(),
                      hasExpectedUsesOfNoEscapePartialApply) &&
         "noescape partial_apply has unexpected use!");

  // The argument index in the called function.
  ApplySite site(apply);
  unsigned calleeArgumentIndex = site.getCalleeArgIndex(*applyArgumentOperand);

  processCall(callerInfo, callerArgumentIndex, calleeFunction,
              calleeArgumentIndex, order);
}

void AccessSummaryAnalysis::processFullApply(FunctionInfo *callerInfo,
                                             unsigned callerArgumentIndex,
                                             FullApplySite apply,
                                             Operand *argumentOperand,
                                             FunctionOrder &order) {
  unsigned operandNumber = argumentOperand->getOperandNumber();
  assert(operandNumber > 0 && "Summarizing apply for non-argument?");

  unsigned calleeArgumentIndex = operandNumber - 1;
  SILFunction *callee = apply.getCalleeFunction();
  // We can't apply a summary for function whose body we can't see.
  // Since user-provided closures are always in the same module as their callee
  // This likely indicates a missing begin_access before an open-coded
  // call.
  if (!callee || callee->empty())
    return;

  processCall(callerInfo, callerArgumentIndex, callee, calleeArgumentIndex,
              order);
}

void AccessSummaryAnalysis::processCall(FunctionInfo *callerInfo,
                                        unsigned callerArgumentIndex,
                                        SILFunction *callee,
                                        unsigned argumentIndex,
                                        FunctionOrder &order) {
  // Record the flow of an argument from  the caller to the callee so that
  // the interprocedural analysis can iterate to a fixpoint.
  FunctionInfo *calleeInfo = getFunctionInfo(callee);
  ArgumentFlow flow = {callerArgumentIndex, argumentIndex, calleeInfo};
  callerInfo->recordFlow(flow);
  if (!calleeInfo->isVisited()) {
    processFunction(calleeInfo, order);
    order.tryToSchedule(calleeInfo);
  }

  propagateFromCalleeToCaller(callerInfo, flow);
}

bool AccessSummaryAnalysis::ArgumentSummary::mergeWith(SILAccessKind otherKind,
                                                        SILLocation otherLoc) {
  // In the lattice, a modification-like accesses subsume a read access or no
  // access.
  if (!Kind.hasValue() ||
      (*Kind == SILAccessKind::Read && otherKind != SILAccessKind::Read)) {
    Kind = otherKind;
    AccessLoc = otherLoc;
    return true;
  }

  return false;
}

bool AccessSummaryAnalysis::ArgumentSummary::mergeWith(
    const ArgumentSummary &other) {
  if (other.Kind.hasValue())
    return mergeWith(*other.Kind, other.AccessLoc);
  return false;
}

void AccessSummaryAnalysis::recompute(FunctionInfo *initial) {
  allocNewUpdateID();

  FunctionOrder order(getCurrentUpdateID());

  // Summarize the function and its callees.
  processFunction(initial, order);

  // Build the bottom-up order.
  order.tryToSchedule(initial);
  order.finishScheduling();

  // Iterate the interprocedural analysis to a fixed point.
  bool needAnotherIteration;
  do {
    needAnotherIteration = false;
    for (FunctionInfo *calleeInfo : order) {
      for (const auto &callerEntry : calleeInfo->getCallers()) {
        assert(callerEntry.isValid());
        if (!order.wasRecomputedWithCurrentUpdateID(calleeInfo))
          continue;

        FunctionInfo *callerInfo = callerEntry.Caller;

        // Propagate from callee to caller.
        for (const auto &argumentFlow : callerInfo->getArgumentFlows()) {
          if (argumentFlow.CalleeFunctionInfo != calleeInfo)
            continue;

          bool changed = propagateFromCalleeToCaller(callerInfo, argumentFlow);
          if (changed && !callerInfo->isScheduledAfter(calleeInfo)) {
            needAnotherIteration = true;
          }
        }
      }
    }
  } while (needAnotherIteration);
}

StringRef AccessSummaryAnalysis::ArgumentSummary::getDescription() const {
  if (Optional<SILAccessKind> kind = getAccessKind()) {
    return getSILAccessKindName(*kind);
  }

  return "none";
}

bool AccessSummaryAnalysis::propagateFromCalleeToCaller(
    FunctionInfo *callerInfo, ArgumentFlow flow) {
  // For a given flow from a caller's argument to a callee's argument,
  // propagate the argument summary information to the caller.

  FunctionInfo *calleeInfo = flow.CalleeFunctionInfo;
  const auto &calleeArgument =
      calleeInfo->getSummary().getAccessForArgument(flow.CalleeArgumentIndex);
  auto &callerArgument =
      callerInfo->getSummary().getAccessForArgument(flow.CallerArgumentIndex);

  bool changed = callerArgument.mergeWith(calleeArgument);
  return changed;
}

AccessSummaryAnalysis::FunctionInfo *
AccessSummaryAnalysis::getFunctionInfo(SILFunction *F) {
  FunctionInfo *&FInfo = FunctionInfos[F];
  if (!FInfo) {
    FInfo = new (Allocator.Allocate()) FunctionInfo(F);
  }
  return FInfo;
}

const AccessSummaryAnalysis::FunctionSummary &
AccessSummaryAnalysis::getOrCreateSummary(SILFunction *fn) {
  FunctionInfo *info = getFunctionInfo(fn);
  if (!info->isValid())
    recompute(info);

  return info->getSummary();
}

void AccessSummaryAnalysis::AccessSummaryAnalysis::invalidate() {
  FunctionInfos.clear();
  Allocator.DestroyAll();
  delete SubPathTrie;
  SubPathTrie = new IndexTrieNode();
}

void AccessSummaryAnalysis::invalidate(SILFunction *F, InvalidationKind K) {
  FunctionInfos.erase(F);
}

SILAnalysis *swift::createAccessSummaryAnalysis(SILModule *M) {
  return new AccessSummaryAnalysis();
}

raw_ostream &swift::
operator<<(raw_ostream &os,
           const AccessSummaryAnalysis::FunctionSummary &summary) {
  unsigned argCount = summary.getArgumentCount();
  os << "(";

  if (argCount > 0) {
    os << summary.getAccessForArgument(0).getDescription();
    for (unsigned i = 1; i < argCount; i++) {
      os << ",  " << summary.getAccessForArgument(i).getDescription();
    }
  }

  os << ")";
  return os;
}
<|endoftext|>


<commit_before>/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
 *
 * For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/

#pragma once

#include "g3log/logmessage.hpp"

namespace g3 {
   namespace internal {

      struct SinkWrapper {
         virtual ~SinkWrapper() { }
         virtual void send(LogMessageMover msg) = 0;
      };
   }
}

<commit_msg>compiles on arm<commit_after>/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
 *
 * For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/

#pragma once

#include "g3log/logmessage.hpp"

namespace g3 {
   namespace internal {

      struct SinkWrapper {
         virtual ~SinkWrapper() { }
         virtual void send(LogMessageMover msg) { }
      };
   }
}

<|endoftext|>


<commit_before>
/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Classes: PDEFoamDistr                                                          *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      The TFDSITR class provides an interface between the Binary search tree    *
 *      and the PDEFoam object.  In order to build-up the foam one needs to       *
 *      calculate the density of events at a given point (sampling during         *
 *      Foam build-up).  The function PDEFoamDistr::Density() does this job.  It  *
 *      uses a binary search tree, filled with training events, in order to       *
 *      provide this density.                                                     *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Tancredi Carli   - CERN, Switzerland                                      *
 *      Dominik Dannheim - CERN, Switzerland                                      *
 *      S. Jadach        - Institute of Nuclear Physics, Cracow, Poland           *
 *      Alexander Voigt  - CERN, Switzerland                                      *
 *      Peter Speckmayer - CERN, Switzerland                                      *
 *                                                                                *
 * Copyright (c) 2008:                                                            *
 *      CERN, Switzerland                                                         *
 *      MPI-K Heidelberg, Germany                                                 *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

#ifndef ROOT_TMath
#include "TMath.h"
#endif

#ifndef ROOT_TMVA_PDEFoamDistr
#include "TMVA/PDEFoamDistr.h"
#endif

ClassImp(TMVA::PDEFoamDistr)

//_____________________________________________________________________
TMVA::PDEFoamDistr::PDEFoamDistr()
   : TObject(),
     fDim(-1),
     fXmin(0),
     fXmax(0),
     fVolFrac(-1.),
     fBst(NULL),
     fDensityCalc(kEVENT_DENSITY), // default: fill event density to BinarySearchTree
     fSignalClass(1),
     fBackgroundClass(0),
     fLogger( new MsgLogger("PDEFoamDistr"))
{}

//_____________________________________________________________________
TMVA::PDEFoamDistr::~PDEFoamDistr()
{
   if (fBst)  delete fBst;
   if (fXmin) delete [] fXmin;  fXmin=0;
   if (fXmax) delete [] fXmax;  fXmax=0;
   delete fLogger;
}

//_____________________________________________________________________
TMVA::PDEFoamDistr::PDEFoamDistr(const PDEFoamDistr &distr)
   : TObject(),
     fDim             (distr.fDim),
     fXmin            (distr.fXmin),
     fXmax            (distr.fXmax),
     fVolFrac         (distr.fVolFrac),
     fBst             (distr.fBst),
     fDensityCalc     (kEVENT_DENSITY), // default: fill event density to BinarySearchTree
     fSignalClass     (distr.fSignalClass),
     fBackgroundClass (distr.fBackgroundClass),
     fLogger( new MsgLogger("PDEFoamDistr"))
{
   // Copy constructor
   Log() << kFATAL << "COPY CONSTRUCTOR NOT IMPLEMENTED" << Endl;
}

//_____________________________________________________________________
void TMVA::PDEFoamDistr::Initialize( Int_t ndim )
{
   // Initialisation procedure of internal foam density.
   // Set dimension to 'ndim' and create BinarySearchTree.

   SetDim(ndim); // set dimension of BST

   if (fBst) delete fBst;
   fBst = new TMVA::BinarySearchTree();

   if (!fBst){
      Log() << kFATAL << "<PDEFoamDistr::Initialize> "
            << "ERROR: an not create binary tree !" << Endl;
   }

   fBst->SetPeriode(fDim);
}

//_____________________________________________________________________
void TMVA::PDEFoamDistr::SetDim(Int_t idim)
{
   // set dimension of distribution

   fDim = idim;
   if (fXmin) delete [] fXmin;
   if (fXmax) delete [] fXmax;
   fXmin = new Float_t[fDim];
   fXmax = new Float_t[fDim];
   return;
}

//_____________________________________________________________________
void TMVA::PDEFoamDistr::FillBinarySearchTree( const Event* ev, EFoamType ft, Bool_t NoNegWeights )
{
   // This method creates an TMVA::Event and inserts it into the
   // binary search tree.
   //
   // If 'NoNegWeights' is true, an event with negative weight will
   // not be filled into the foam.  (Default value: false)

   if((NoNegWeights && ev->GetWeight()<=0) || ev->GetOriginalWeight()==0)
      return;

   TMVA::Event *event = new TMVA::Event(*ev);

   // set event class and normalization
   if (ft==kSeparate || ft==kDiscr){
      event->SetClass(ev->GetClass()==fSignalClass ? fSignalClass : fBackgroundClass);
   } else if (ft==kMultiTarget){
      // since in multi target regression targets are handled like
      // variables, remove targets and add them to the event variabels
      std::vector<Float_t> targets = ev->GetTargets();
      for (UInt_t i = 0; i < targets.size(); i++)
         event->SetVal(i+ev->GetValues().size(), targets.at(i));
      event->GetTargets().clear();
      event->SetClass(fSignalClass);
   }
   fBst->Insert(event);
}

//_____________________________________________________________________
Double_t TMVA::PDEFoamDistr::Density( Double_t *Xarg, Double_t &event_density )
{
   // This function is needed during the foam buildup.
   // It return a certain density depending on the selected classification
   // or regression options:
   //
   // In case of separated foams (classification) or multi target regression:
   //  - returns event density within volume (specified by VolFrac)
   // In case of unified foams: (classification)
   //  - returns discriminator (N_sig)/(N_sig + N_bg) divided by volume
   //    (specified by VolFrac)
   // In case of mono target regression:
   //  - returns average target value within volume divided by volume
   //    (specified by VolFrac)

   if (!fBst)
      Log() << kFATAL << "<PDEFoamDistr::Density()> Binary tree not found!"<< Endl;

   // make the variable Xarg transform, since Foam only knows about x=[0,1]
   // transformation [0, 1] --> [xmin, xmax]
   for (Int_t idim=0; idim<fDim; idim++)
      Xarg[idim] = VarTransformInvers(idim, Xarg[idim]);

   //create volume around point to be found
   std::vector<Double_t> lb(fDim);
   std::vector<Double_t> ub(fDim);

   // probevolume relative to hypercube with edge length 1:
   static const Double_t probevolume_inv = TMath::Power((fVolFrac/2), fDim);

   // set upper and lower bound for search volume
   for (Int_t idim = 0; idim < fDim; idim++) {
      Double_t volsize=(fXmax[idim] - fXmin[idim]) / fVolFrac;
      lb[idim] = Xarg[idim] - volsize;
      ub[idim] = Xarg[idim] + volsize;
   }

   TMVA::Volume volume(&lb, &ub);                        // volume to search in
   std::vector<const TMVA::BinarySearchTreeNode*> nodes; // BST nodes found

   // do range searching
   fBst->SearchVolume(&volume, &nodes);

   // normalized density: (number of counted events) / volume / (total
   // number of events) should be ~1 on average
   const Double_t count = (Double_t) (nodes.size()); // number of events found

   // store density based on total number of events
   event_density = count * probevolume_inv;

   Double_t weighted_count = 0.; // number of events found (sum of weights!)
   for (UInt_t j=0; j<nodes.size(); j++)
      weighted_count += (nodes.at(j))->GetWeight();

   if (FillDiscriminator()){ // calc number of signal events in nodes
      Double_t N_sig = 0;    // number of target events found
      // now sum over all nodes->IsSignal;
      for (Int_t j=0; j<count; j++){
         N_sig += ((nodes.at(j))->IsSignal()?1.:0.) * (nodes.at(j))->GetWeight();
      }
      return (N_sig/(weighted_count+0.1))*probevolume_inv; // return:  (N_sig/N_total) / (cell_volume)
   }
   else if (FillTarget0()){ // calc sum of weighted target values
      Double_t N_tar = 0;   // number of target events found
      // now sum over all nodes->GetTarget(0);
      for (Int_t j=0; j<count; j++) {
         N_tar += ((nodes.at(j))->GetTargets()).at(0) * ((nodes.at(j))->GetWeight());
      }
      return (N_tar/(weighted_count+0.1))*probevolume_inv; // return:  (N_tar/N_total) / (cell_volume)
   }

   return ((weighted_count+0.1)*probevolume_inv); // return:  N_total(weighted) / cell_volume
}
<commit_msg>fix clang warning (operands of ? are integers of different signs).<commit_after>
/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Classes: PDEFoamDistr                                                          *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      The TFDSITR class provides an interface between the Binary search tree    *
 *      and the PDEFoam object.  In order to build-up the foam one needs to       *
 *      calculate the density of events at a given point (sampling during         *
 *      Foam build-up).  The function PDEFoamDistr::Density() does this job.  It  *
 *      uses a binary search tree, filled with training events, in order to       *
 *      provide this density.                                                     *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Tancredi Carli   - CERN, Switzerland                                      *
 *      Dominik Dannheim - CERN, Switzerland                                      *
 *      S. Jadach        - Institute of Nuclear Physics, Cracow, Poland           *
 *      Alexander Voigt  - CERN, Switzerland                                      *
 *      Peter Speckmayer - CERN, Switzerland                                      *
 *                                                                                *
 * Copyright (c) 2008:                                                            *
 *      CERN, Switzerland                                                         *
 *      MPI-K Heidelberg, Germany                                                 *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

#ifndef ROOT_TMath
#include "TMath.h"
#endif

#ifndef ROOT_TMVA_PDEFoamDistr
#include "TMVA/PDEFoamDistr.h"
#endif

ClassImp(TMVA::PDEFoamDistr)

//_____________________________________________________________________
TMVA::PDEFoamDistr::PDEFoamDistr()
   : TObject(),
     fDim(-1),
     fXmin(0),
     fXmax(0),
     fVolFrac(-1.),
     fBst(NULL),
     fDensityCalc(kEVENT_DENSITY), // default: fill event density to BinarySearchTree
     fSignalClass(1),
     fBackgroundClass(0),
     fLogger( new MsgLogger("PDEFoamDistr"))
{}

//_____________________________________________________________________
TMVA::PDEFoamDistr::~PDEFoamDistr()
{
   if (fBst)  delete fBst;
   if (fXmin) delete [] fXmin;  fXmin=0;
   if (fXmax) delete [] fXmax;  fXmax=0;
   delete fLogger;
}

//_____________________________________________________________________
TMVA::PDEFoamDistr::PDEFoamDistr(const PDEFoamDistr &distr)
   : TObject(),
     fDim             (distr.fDim),
     fXmin            (distr.fXmin),
     fXmax            (distr.fXmax),
     fVolFrac         (distr.fVolFrac),
     fBst             (distr.fBst),
     fDensityCalc     (kEVENT_DENSITY), // default: fill event density to BinarySearchTree
     fSignalClass     (distr.fSignalClass),
     fBackgroundClass (distr.fBackgroundClass),
     fLogger( new MsgLogger("PDEFoamDistr"))
{
   // Copy constructor
   Log() << kFATAL << "COPY CONSTRUCTOR NOT IMPLEMENTED" << Endl;
}

//_____________________________________________________________________
void TMVA::PDEFoamDistr::Initialize( Int_t ndim )
{
   // Initialisation procedure of internal foam density.
   // Set dimension to 'ndim' and create BinarySearchTree.

   SetDim(ndim); // set dimension of BST

   if (fBst) delete fBst;
   fBst = new TMVA::BinarySearchTree();

   if (!fBst){
      Log() << kFATAL << "<PDEFoamDistr::Initialize> "
            << "ERROR: an not create binary tree !" << Endl;
   }

   fBst->SetPeriode(fDim);
}

//_____________________________________________________________________
void TMVA::PDEFoamDistr::SetDim(Int_t idim)
{
   // set dimension of distribution

   fDim = idim;
   if (fXmin) delete [] fXmin;
   if (fXmax) delete [] fXmax;
   fXmin = new Float_t[fDim];
   fXmax = new Float_t[fDim];
   return;
}

//_____________________________________________________________________
void TMVA::PDEFoamDistr::FillBinarySearchTree( const Event* ev, EFoamType ft, Bool_t NoNegWeights )
{
   // This method creates an TMVA::Event and inserts it into the
   // binary search tree.
   //
   // If 'NoNegWeights' is true, an event with negative weight will
   // not be filled into the foam.  (Default value: false)

   if((NoNegWeights && ev->GetWeight()<=0) || ev->GetOriginalWeight()==0)
      return;

   TMVA::Event *event = new TMVA::Event(*ev);

   // set event class and normalization
   if (ft==kSeparate || ft==kDiscr){
      event->SetClass(ev->GetClass()==fSignalClass ? fSignalClass : (UInt_t)fBackgroundClass);
   } else if (ft==kMultiTarget){
      // since in multi target regression targets are handled like
      // variables, remove targets and add them to the event variabels
      std::vector<Float_t> targets = ev->GetTargets();
      for (UInt_t i = 0; i < targets.size(); i++)
         event->SetVal(i+ev->GetValues().size(), targets.at(i));
      event->GetTargets().clear();
      event->SetClass(fSignalClass);
   }
   fBst->Insert(event);
}

//_____________________________________________________________________
Double_t TMVA::PDEFoamDistr::Density( Double_t *Xarg, Double_t &event_density )
{
   // This function is needed during the foam buildup.
   // It return a certain density depending on the selected classification
   // or regression options:
   //
   // In case of separated foams (classification) or multi target regression:
   //  - returns event density within volume (specified by VolFrac)
   // In case of unified foams: (classification)
   //  - returns discriminator (N_sig)/(N_sig + N_bg) divided by volume
   //    (specified by VolFrac)
   // In case of mono target regression:
   //  - returns average target value within volume divided by volume
   //    (specified by VolFrac)

   if (!fBst)
      Log() << kFATAL << "<PDEFoamDistr::Density()> Binary tree not found!"<< Endl;

   // make the variable Xarg transform, since Foam only knows about x=[0,1]
   // transformation [0, 1] --> [xmin, xmax]
   for (Int_t idim=0; idim<fDim; idim++)
      Xarg[idim] = VarTransformInvers(idim, Xarg[idim]);

   //create volume around point to be found
   std::vector<Double_t> lb(fDim);
   std::vector<Double_t> ub(fDim);

   // probevolume relative to hypercube with edge length 1:
   static const Double_t probevolume_inv = TMath::Power((fVolFrac/2), fDim);

   // set upper and lower bound for search volume
   for (Int_t idim = 0; idim < fDim; idim++) {
      Double_t volsize=(fXmax[idim] - fXmin[idim]) / fVolFrac;
      lb[idim] = Xarg[idim] - volsize;
      ub[idim] = Xarg[idim] + volsize;
   }

   TMVA::Volume volume(&lb, &ub);                        // volume to search in
   std::vector<const TMVA::BinarySearchTreeNode*> nodes; // BST nodes found

   // do range searching
   fBst->SearchVolume(&volume, &nodes);

   // normalized density: (number of counted events) / volume / (total
   // number of events) should be ~1 on average
   const Double_t count = (Double_t) (nodes.size()); // number of events found

   // store density based on total number of events
   event_density = count * probevolume_inv;

   Double_t weighted_count = 0.; // number of events found (sum of weights!)
   for (UInt_t j=0; j<nodes.size(); j++)
      weighted_count += (nodes.at(j))->GetWeight();

   if (FillDiscriminator()){ // calc number of signal events in nodes
      Double_t N_sig = 0;    // number of target events found
      // now sum over all nodes->IsSignal;
      for (Int_t j=0; j<count; j++){
         N_sig += ((nodes.at(j))->IsSignal()?1.:0.) * (nodes.at(j))->GetWeight();
      }
      return (N_sig/(weighted_count+0.1))*probevolume_inv; // return:  (N_sig/N_total) / (cell_volume)
   }
   else if (FillTarget0()){ // calc sum of weighted target values
      Double_t N_tar = 0;   // number of target events found
      // now sum over all nodes->GetTarget(0);
      for (Int_t j=0; j<count; j++) {
         N_tar += ((nodes.at(j))->GetTargets()).at(0) * ((nodes.at(j))->GetWeight());
      }
      return (N_tar/(weighted_count+0.1))*probevolume_inv; // return:  (N_tar/N_total) / (cell_volume)
   }

   return ((weighted_count+0.1)*probevolume_inv); // return:  N_total(weighted) / cell_volume
}
<|endoftext|>


<commit_before>#include "gamelib/core/Game.hpp"
#include <SFML/Graphics.hpp>
#include <climits>
#include "gamelib/core/GameState.hpp"
#include "gamelib/utils/log.hpp"
#include "gamelib/core/event/EventManager.hpp"
#include "gamelib/events/SFMLEvent.hpp"
#include "gamelib/core/input/InputSystem.hpp"
#include "imgui-SFML.h"
#include "imgui.h"

namespace gamelib
{
    Game::Game() :
        bgcolor(sf::Color::Black),
        closebutton(true),
        escclose(true),
        unfocusPause(true),
        _frametime(0),
        _rendertime(0),
        _updatetime(0),
        _size(640, 480),
        _maxfps(60),
        _title("Unnamed Game"),
        _repeatkeys(false),
        _vsync(true),
        _initialized(false)
    {
#define WIN_PROP_SET_LAMBDA(varname, winfunc) \
        +[](const decltype(varname)* val, Game* self) { \
            self->varname = *val; \
            if (self->_window.isOpen()) \
                self->_window.winfunc(*val); \
        }

        auto setSize = +[](const math::Vec2i* val, Game* self) {
            self->resize(sf::Vector2u(val->x, val->y));
        };

        _props.registerProperty("bgcolor", bgcolor);
        _props.registerProperty("closebutton", closebutton);
        _props.registerProperty("escclose", escclose);
        _props.registerProperty("unfocusPause", unfocusPause);
        _props.registerProperty("size", _size, setSize, this);
        _props.registerProperty("maxfps", _maxfps, WIN_PROP_SET_LAMBDA(_maxfps, setFramerateLimit), this, 0, INT_MAX);
        _props.registerProperty("vsync", _vsync, WIN_PROP_SET_LAMBDA(_vsync, setVerticalSyncEnabled), this);
        _props.registerProperty("title", _title, WIN_PROP_SET_LAMBDA(_title, setTitle), this);
        _props.registerProperty("repeatkeys", _repeatkeys, WIN_PROP_SET_LAMBDA(_repeatkeys, setKeyRepeatEnabled), this);
    }

    Game::~Game()
    {
        destroy();
    }

    bool Game::init()
    {
        LOG("Initializing game...");
        _window.create(sf::VideoMode(_size.x, _size.y), _title, sf::Style::Close);
        _window.setFramerateLimit(_maxfps);
        _window.setVerticalSyncEnabled(_vsync);
        _window.setKeyRepeatEnabled(_repeatkeys);

        ImGui::SFML::Init(_window);

        // ImGui::StyleColorsClassic();
        ImGui::GetStyle().WindowBorderSize = 0;
        ImGui::GetStyle().WindowRounding = 0;
        ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;
        ImGui::GetIO().ConfigDockingWithShift = false;
        ImGui::GetIO().ConfigWindowsResizeFromEdges = true;

        _initialized = true;

        return true;
    }

    auto Game::isInitialized() const -> bool
    {
        return _initialized;
    }

    void Game::run()
    {
        if (!isInitialized())
        {
            LOG_ERROR("Game is not initialized");
            return;
        }

        sf::Clock clock, detailclock;
        sf::Event ev;

        while (_window.isOpen())
        {
            clock.restart();
            detailclock.restart();

            auto inputsys = getSubsystem<InputSystem>();
            if (inputsys)
                inputsys->beginFrame();

            while (_window.pollEvent(ev))
            {
                if (inputsys)
                    inputsys->process(ev);

                ImGui::SFML::ProcessEvent(ev);

                // TODO: clear keyboard

                auto evmgr = getSubsystem<EventManager>();
                if (evmgr)
                    evmgr->triggerEvent(SFMLEvent::create(ev));

                if (closebutton && ev.type == sf::Event::Closed)
                {
                    close();
                    return;
                }
            }

            if (_window.hasFocus() || !unfocusPause)
            {
                ImGui::SFML::Update(_window, sf::seconds(_frametime));

                bool frozen = false;
                for (auto it = _states.rbegin(), end = _states.rend(); it != end; ++it)
                {
                    auto state = (*it).get();
                    if (state->flags & gamestate_paused)
                        continue;

                    if (!frozen || state->flags & gamestate_forceupdate)
                        state->update(_frametime);

                    if (state->flags & gamestate_freeze)
                        frozen = true;
                }

                if (escclose && inputsys && inputsys->isKeyPressed(sf::Keyboard::Escape))
                {
                    close();
                    return;
                }
            }

            _updatetime = detailclock.getElapsedTime().asMilliseconds() / 1000.f;
            detailclock.restart();

            _window.resetGLStates(); // without this things start randomly disappearing
            _window.clear(bgcolor);

            if (_vsync)
                detailclock.restart();

            for (auto& i : _states)
                i->render(_window);

            ImGui::SFML::Render(_window);

            // TODO: implement own fps capping.
            // SFML caps inside window.display(), so it's impossible to get the exact render time
            if (!_vsync)
                _rendertime = detailclock.getElapsedTime().asMilliseconds() / 1000.0f;

            _window.display();

            if (_vsync)
                _rendertime = detailclock.getElapsedTime().asMilliseconds() / 1000.0f;

            // Get elapsed time
            _frametime = clock.getElapsedTime().asMilliseconds() / 1000.0f;
        }
    }

    void Game::close()
    {
        if (_window.isOpen())
        {
            _window.close();
            LOG_DEBUG("Game window closed");
        }
    }

    void Game::destroy()
    {
        if (!isInitialized())
            return;

        close();

        if (!_states.empty())
        {
            LOG_DEBUG("Closing game states...");
            for (auto& i : _states)
                i->quit();
            _states.clear();
        }

        ImGui::SFML::Shutdown();
        _initialized = false;
    }

    bool Game::loadFromJson(const Json::Value& node)
    {
        return _props.loadFromJson(node);
    }

    void Game::writeToJson(Json::Value& node) const
    {
        _props.writeToJson(node);
    }

    void Game::pushState(std::unique_ptr<GameState> state)
    {
        if (!state->init(this))
        {
            LOG_ERROR("Failed to initialize game state");
            return;
        }
        _states.push_back(std::move(state));
        LOG_DEBUG("Game state added");
    }

    void Game::popState()
    {
        _states.back()->quit();
        _states.pop_back();
    }

    GameState* Game::pullState() const
    {
        return _states.back().get();
    }

    float Game::getFrametime() const
    {
        return _frametime;
    }

    float Game::getRealFrametime() const
    {
        return _rendertime + _updatetime;
    }

    float Game::getRenderTime() const
    {
        return _rendertime;
    }

    float Game::getUpdateTime() const
    {
        return _updatetime;
    }

    sf::RenderWindow& Game::getWindow()
    {
        return _window;
    }

    const PropertyContainer& Game::getProperties() const
    {
        return _props;
    }

    void Game::resize(const sf::Vector2u& size)
    {
        if (size.x <= 0 || size.y <= 0)
        {
            LOG_ERROR("Invalid window size: ", size.x, "x", size.y);
            return;
        }

        _size.fill(size.x, size.y);

        if (_window.isOpen())
        {
            auto diff = size - _window.getSize();
            auto pos = _window.getPosition();
            pos.x -= diff.x / 2;
            pos.y -= diff.y / 2;

            _window.setSize(size);
            _window.setPosition(pos);
            _window.setView(sf::View(sf::FloatRect(0, 0, size.x, size.y)));
        }

        // Don't create a new window, as it could lead to problems
        // if (size != _window.getSize())
        // {
        //     _window.close();
        //     _window.create(sf::VideoMode(size.x, size.y), game_title, sf::Style::Close);
        // }
    }
}

<commit_msg>Make game window resizable<commit_after>#include "gamelib/core/Game.hpp"
#include <SFML/Graphics.hpp>
#include <climits>
#include "gamelib/core/GameState.hpp"
#include "gamelib/utils/log.hpp"
#include "gamelib/core/event/EventManager.hpp"
#include "gamelib/events/SFMLEvent.hpp"
#include "gamelib/core/input/InputSystem.hpp"
#include "imgui-SFML.h"
#include "imgui.h"

namespace gamelib
{
    Game::Game() :
        bgcolor(sf::Color::Black),
        closebutton(true),
        escclose(true),
        unfocusPause(true),
        _frametime(0),
        _rendertime(0),
        _updatetime(0),
        _size(640, 480),
        _maxfps(60),
        _title("Unnamed Game"),
        _repeatkeys(false),
        _vsync(true),
        _initialized(false)
    {
#define WIN_PROP_SET_LAMBDA(varname, winfunc) \
        +[](const decltype(varname)* val, Game* self) { \
            self->varname = *val; \
            if (self->_window.isOpen()) \
                self->_window.winfunc(*val); \
        }

        auto setSize = +[](const math::Vec2i* val, Game* self) {
            self->resize(sf::Vector2u(val->x, val->y));
        };

        _props.registerProperty("bgcolor", bgcolor);
        _props.registerProperty("closebutton", closebutton);
        _props.registerProperty("escclose", escclose);
        _props.registerProperty("unfocusPause", unfocusPause);
        _props.registerProperty("size", _size, setSize, this);
        _props.registerProperty("maxfps", _maxfps, WIN_PROP_SET_LAMBDA(_maxfps, setFramerateLimit), this, 0, INT_MAX);
        _props.registerProperty("vsync", _vsync, WIN_PROP_SET_LAMBDA(_vsync, setVerticalSyncEnabled), this);
        _props.registerProperty("title", _title, WIN_PROP_SET_LAMBDA(_title, setTitle), this);
        _props.registerProperty("repeatkeys", _repeatkeys, WIN_PROP_SET_LAMBDA(_repeatkeys, setKeyRepeatEnabled), this);
    }

    Game::~Game()
    {
        destroy();
    }

    bool Game::init()
    {
        LOG("Initializing game...");
        _window.create(sf::VideoMode(_size.x, _size.y), _title);
        _window.setFramerateLimit(_maxfps);
        _window.setVerticalSyncEnabled(_vsync);
        _window.setKeyRepeatEnabled(_repeatkeys);

        ImGui::SFML::Init(_window);

        // ImGui::StyleColorsClassic();
        ImGui::GetStyle().WindowBorderSize = 0;
        ImGui::GetStyle().WindowRounding = 0;
        ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;
        ImGui::GetIO().ConfigDockingWithShift = false;
        ImGui::GetIO().ConfigWindowsResizeFromEdges = true;

        _initialized = true;

        return true;
    }

    auto Game::isInitialized() const -> bool
    {
        return _initialized;
    }

    void Game::run()
    {
        if (!isInitialized())
        {
            LOG_ERROR("Game is not initialized");
            return;
        }

        sf::Clock clock, detailclock;
        sf::Event ev;

        while (_window.isOpen())
        {
            clock.restart();
            detailclock.restart();

            auto inputsys = getSubsystem<InputSystem>();
            if (inputsys)
                inputsys->beginFrame();

            while (_window.pollEvent(ev))
            {
                if (inputsys)
                    inputsys->process(ev);

                ImGui::SFML::ProcessEvent(ev);

                // TODO: clear keyboard

                auto evmgr = getSubsystem<EventManager>();
                if (evmgr)
                    evmgr->triggerEvent(SFMLEvent::create(ev));

                if (closebutton && ev.type == sf::Event::Closed)
                {
                    close();
                    return;
                }
            }

            if (_window.hasFocus() || !unfocusPause)
            {
                ImGui::SFML::Update(_window, sf::seconds(_frametime));

                bool frozen = false;
                for (auto it = _states.rbegin(), end = _states.rend(); it != end; ++it)
                {
                    auto state = (*it).get();
                    if (state->flags & gamestate_paused)
                        continue;

                    if (!frozen || state->flags & gamestate_forceupdate)
                        state->update(_frametime);

                    if (state->flags & gamestate_freeze)
                        frozen = true;
                }

                if (escclose && inputsys && inputsys->isKeyPressed(sf::Keyboard::Escape))
                {
                    close();
                    return;
                }
            }

            _updatetime = detailclock.getElapsedTime().asMilliseconds() / 1000.f;
            detailclock.restart();

            _window.resetGLStates(); // without this things start randomly disappearing
            _window.clear(bgcolor);

            if (_vsync)
                detailclock.restart();

            for (auto& i : _states)
                i->render(_window);

            ImGui::SFML::Render(_window);

            // TODO: implement own fps capping.
            // SFML caps inside window.display(), so it's impossible to get the exact render time
            if (!_vsync)
                _rendertime = detailclock.getElapsedTime().asMilliseconds() / 1000.0f;

            _window.display();

            if (_vsync)
                _rendertime = detailclock.getElapsedTime().asMilliseconds() / 1000.0f;

            // Get elapsed time
            _frametime = clock.getElapsedTime().asMilliseconds() / 1000.0f;
        }
    }

    void Game::close()
    {
        if (_window.isOpen())
        {
            _window.close();
            LOG_DEBUG("Game window closed");
        }
    }

    void Game::destroy()
    {
        if (!isInitialized())
            return;

        close();

        if (!_states.empty())
        {
            LOG_DEBUG("Closing game states...");
            for (auto& i : _states)
                i->quit();
            _states.clear();
        }

        ImGui::SFML::Shutdown();
        _initialized = false;
    }

    bool Game::loadFromJson(const Json::Value& node)
    {
        return _props.loadFromJson(node);
    }

    void Game::writeToJson(Json::Value& node) const
    {
        _props.writeToJson(node);
    }

    void Game::pushState(std::unique_ptr<GameState> state)
    {
        if (!state->init(this))
        {
            LOG_ERROR("Failed to initialize game state");
            return;
        }
        _states.push_back(std::move(state));
        LOG_DEBUG("Game state added");
    }

    void Game::popState()
    {
        _states.back()->quit();
        _states.pop_back();
    }

    GameState* Game::pullState() const
    {
        return _states.back().get();
    }

    float Game::getFrametime() const
    {
        return _frametime;
    }

    float Game::getRealFrametime() const
    {
        return _rendertime + _updatetime;
    }

    float Game::getRenderTime() const
    {
        return _rendertime;
    }

    float Game::getUpdateTime() const
    {
        return _updatetime;
    }

    sf::RenderWindow& Game::getWindow()
    {
        return _window;
    }

    const PropertyContainer& Game::getProperties() const
    {
        return _props;
    }

    void Game::resize(const sf::Vector2u& size)
    {
        if (size.x <= 0 || size.y <= 0)
        {
            LOG_ERROR("Invalid window size: ", size.x, "x", size.y);
            return;
        }

        _size.fill(size.x, size.y);

        if (_window.isOpen())
        {
            auto diff = size - _window.getSize();
            auto pos = _window.getPosition();
            pos.x -= diff.x / 2;
            pos.y -= diff.y / 2;

            _window.setSize(size);
            _window.setPosition(pos);
            _window.setView(sf::View(sf::FloatRect(0, 0, size.x, size.y)));
        }

        // Don't create a new window, as it could lead to problems
        // if (size != _window.getSize())
        // {
        //     _window.close();
        //     _window.create(sf::VideoMode(size.x, size.y), game_title, sf::Style::Close);
        // }
    }
}

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

#include <opengl/program.hxx>

#include <vcl/opengl/OpenGLHelper.hxx>

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>

OpenGLProgram::OpenGLProgram() :
    mnId( 0 ),
    mnEnabledAttribs( 0 ),
    mnPositionAttrib( SAL_MAX_UINT32 ),
    mnTexCoordAttrib( SAL_MAX_UINT32 ),
    mnAlphaCoordAttrib( SAL_MAX_UINT32 ),
    mbBlending( false )
{
}

OpenGLProgram::~OpenGLProgram()
{
    maUniformLocations.clear();
    if( mnId != 0 )
        glDeleteProgram( mnId );
}

bool OpenGLProgram::Load( const OUString& rVertexShader, const OUString& rFragmentShader )
{
    mnId = OpenGLHelper::LoadShaders( rVertexShader, rFragmentShader );
    return ( mnId != 0 );
}

bool OpenGLProgram::Use()
{
    if( !mnId )
        return false;

    glUseProgram( mnId );
    return true;
}

bool OpenGLProgram::Clean()
{
    // unbind all textures
    if( !maTextures.empty() )
    {
        int nIndex( maTextures.size() - 1 );
        TextureList::reverse_iterator it( maTextures.rbegin() );
        while( it != maTextures.rend() )
        {
            glActiveTexture( GL_TEXTURE0 + nIndex-- );
            it->Unbind();
            it++;
        }
        maTextures.clear();
    }

    // disable any enabled vertex attrib array
    if( mnEnabledAttribs )
    {
        for( int i = 0; i < 32; i++ )
        {
            if( mnEnabledAttribs & ( 1 << i ) )
                glDisableVertexAttribArray( i );
        }
        mnEnabledAttribs = 0;
    }

    // disable blending if enabled
    if( mbBlending )
    {
        mbBlending = false;
        glDisable( GL_BLEND );
    }

    CHECK_GL_ERROR();
    return true;
}

void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData )
{
    if( rAttrib == SAL_MAX_UINT32 )
        rAttrib = glGetAttribLocation( mnId, (char*) rName.getStr() );
    if( (mnEnabledAttribs & ( 1 << rAttrib )) == 0 )
    {
        glEnableVertexAttribArray( rAttrib );
        mnEnabledAttribs |= ( 1 << rAttrib );
    }
    glVertexAttribPointer( rAttrib, 2, GL_FLOAT, GL_FALSE, 0, pData );
}

void OpenGLProgram::SetVertices( const GLvoid* pData )
{
    SetVertexAttrib( mnPositionAttrib, "position", pData );
}

void OpenGLProgram::SetTextureCoord( const GLvoid* pData )
{
    SetVertexAttrib( mnTexCoordAttrib, "tex_coord_in", pData );
}

void OpenGLProgram::SetAlphaCoord( const GLvoid* pData )
{
    SetVertexAttrib( mnAlphaCoordAttrib, "alpha_coord_in", pData );
}

GLuint OpenGLProgram::GetUniformLocation( const OString& rName )
{
    boost::unordered_map<OString, GLuint>::iterator it;

    it = maUniformLocations.find( rName );
    if( it == maUniformLocations.end() )
    {
        GLuint nLocation = glGetUniformLocation( mnId, (char*) rName.getStr() );
        maUniformLocations[rName] = nLocation;
        return nLocation;
    }

    return it->second;
}

void OpenGLProgram::SetUniform1f( const OString& rName, GLfloat v1 )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform1f( nUniform, v1 );
}

void OpenGLProgram::SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform2f( nUniform, v1, v2 );
}

void OpenGLProgram::SetUniform1fv( const OString& rName, GLsizei nCount, GLfloat* aValues )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform1fv( nUniform, nCount, aValues );
}

void OpenGLProgram::SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat* aValues )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform2fv( nUniform, nCount, aValues );
}

void OpenGLProgram::SetColor( const OString& rName, SalColor nColor, sal_uInt8 nTransparency )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) SALCOLOR_RED( nColor )) / 255,
                 ((float) SALCOLOR_GREEN( nColor )) / 255,
                 ((float) SALCOLOR_BLUE( nColor )) / 255,
                 (100 - nTransparency) * (1.0 / 100) );

    if( nTransparency > 0 )
        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

void OpenGLProgram::SetColorf( const OString& rName, SalColor nColor, double fTransparency )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) SALCOLOR_RED( nColor )) / 255,
                 ((float) SALCOLOR_GREEN( nColor )) / 255,
                 ((float) SALCOLOR_BLUE( nColor )) / 255,
                 (1.0f - fTransparency) );

    if( fTransparency > 0.0 )
        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

void OpenGLProgram::SetColor( const OString& rName, const Color& rColor )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) rColor.GetRed()) / 255,
                 ((float) rColor.GetGreen()) / 255,
                 ((float) rColor.GetBlue()) / 255,
                 1.0f - ((float) rColor.GetTransparency()) / 255 );

    if( rColor.GetTransparency() > 0 )
        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

void OpenGLProgram::SetColorWithIntensity( const OString& rName, const Color& rColor, long nFactor )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) rColor.GetRed()) * nFactor / 25500.0,
                 ((float) rColor.GetGreen()) * nFactor / 25500.0,
                 ((float) rColor.GetBlue()) * nFactor / 25500.0,
                 1.0f );
}

void OpenGLProgram::SetTexture( const OString& rName, OpenGLTexture& rTexture )
{
    GLuint nUniform = GetUniformLocation( rName );
    int nIndex = maTextures.size();

    glUniform1i( nUniform, nIndex );
    glActiveTexture( GL_TEXTURE0 + nIndex );
    rTexture.Bind();
    maTextures.push_back( rTexture );
}

void OpenGLProgram::SetTransform(
    const OString& rName,
    const OpenGLTexture& rTexture,
    const basegfx::B2DPoint& rNull,
    const basegfx::B2DPoint& rX,
    const basegfx::B2DPoint& rY )
{
    GLuint nUniform = GetUniformLocation( rName );
    const basegfx::B2DVector aXRel = rX - rNull;
    const basegfx::B2DVector aYRel = rY - rNull;
    const float aValues[] = {
        (float) aXRel.getX()/rTexture.GetWidth(),  (float) aXRel.getY()/rTexture.GetWidth(),  0, 0,
        (float) aYRel.getX()/rTexture.GetHeight(), (float) aYRel.getY()/rTexture.GetHeight(), 0, 0,
        0,                                         0,                                         1, 0,
        (float) rNull.getX(),                      (float) rNull.getY(),                      0, 1 };
    glm::mat4 mMatrix = glm::make_mat4( aValues );
    glUniformMatrix4fv( nUniform, 1, GL_FALSE, glm::value_ptr( mMatrix ) );
}

void OpenGLProgram::SetBlendMode( GLenum nSFactor, GLenum nDFactor )
{
    glEnable( GL_BLEND );
    glBlendFunc( nSFactor, nDFactor );
    mbBlending = true;
}

bool OpenGLProgram::DrawTexture( OpenGLTexture& rTexture )
{
    GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
    GLfloat aTexCoord[8];

    if( !rTexture )
        return false;

    rTexture.GetWholeCoord( aTexCoord );
    SetVertices( aPosition );
    SetTextureCoord( aTexCoord );
    glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
    CHECK_GL_ERROR();

    return true;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#1256664 Division or modulo by float zero<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/.
 */

#include <opengl/program.hxx>

#include <vcl/opengl/OpenGLHelper.hxx>

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>

OpenGLProgram::OpenGLProgram() :
    mnId( 0 ),
    mnEnabledAttribs( 0 ),
    mnPositionAttrib( SAL_MAX_UINT32 ),
    mnTexCoordAttrib( SAL_MAX_UINT32 ),
    mnAlphaCoordAttrib( SAL_MAX_UINT32 ),
    mbBlending( false )
{
}

OpenGLProgram::~OpenGLProgram()
{
    maUniformLocations.clear();
    if( mnId != 0 )
        glDeleteProgram( mnId );
}

bool OpenGLProgram::Load( const OUString& rVertexShader, const OUString& rFragmentShader )
{
    mnId = OpenGLHelper::LoadShaders( rVertexShader, rFragmentShader );
    return ( mnId != 0 );
}

bool OpenGLProgram::Use()
{
    if( !mnId )
        return false;

    glUseProgram( mnId );
    return true;
}

bool OpenGLProgram::Clean()
{
    // unbind all textures
    if( !maTextures.empty() )
    {
        int nIndex( maTextures.size() - 1 );
        TextureList::reverse_iterator it( maTextures.rbegin() );
        while( it != maTextures.rend() )
        {
            glActiveTexture( GL_TEXTURE0 + nIndex-- );
            it->Unbind();
            it++;
        }
        maTextures.clear();
    }

    // disable any enabled vertex attrib array
    if( mnEnabledAttribs )
    {
        for( int i = 0; i < 32; i++ )
        {
            if( mnEnabledAttribs & ( 1 << i ) )
                glDisableVertexAttribArray( i );
        }
        mnEnabledAttribs = 0;
    }

    // disable blending if enabled
    if( mbBlending )
    {
        mbBlending = false;
        glDisable( GL_BLEND );
    }

    CHECK_GL_ERROR();
    return true;
}

void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData )
{
    if( rAttrib == SAL_MAX_UINT32 )
        rAttrib = glGetAttribLocation( mnId, (char*) rName.getStr() );
    if( (mnEnabledAttribs & ( 1 << rAttrib )) == 0 )
    {
        glEnableVertexAttribArray( rAttrib );
        mnEnabledAttribs |= ( 1 << rAttrib );
    }
    glVertexAttribPointer( rAttrib, 2, GL_FLOAT, GL_FALSE, 0, pData );
}

void OpenGLProgram::SetVertices( const GLvoid* pData )
{
    SetVertexAttrib( mnPositionAttrib, "position", pData );
}

void OpenGLProgram::SetTextureCoord( const GLvoid* pData )
{
    SetVertexAttrib( mnTexCoordAttrib, "tex_coord_in", pData );
}

void OpenGLProgram::SetAlphaCoord( const GLvoid* pData )
{
    SetVertexAttrib( mnAlphaCoordAttrib, "alpha_coord_in", pData );
}

GLuint OpenGLProgram::GetUniformLocation( const OString& rName )
{
    boost::unordered_map<OString, GLuint>::iterator it;

    it = maUniformLocations.find( rName );
    if( it == maUniformLocations.end() )
    {
        GLuint nLocation = glGetUniformLocation( mnId, (char*) rName.getStr() );
        maUniformLocations[rName] = nLocation;
        return nLocation;
    }

    return it->second;
}

void OpenGLProgram::SetUniform1f( const OString& rName, GLfloat v1 )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform1f( nUniform, v1 );
}

void OpenGLProgram::SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform2f( nUniform, v1, v2 );
}

void OpenGLProgram::SetUniform1fv( const OString& rName, GLsizei nCount, GLfloat* aValues )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform1fv( nUniform, nCount, aValues );
}

void OpenGLProgram::SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat* aValues )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform2fv( nUniform, nCount, aValues );
}

void OpenGLProgram::SetColor( const OString& rName, SalColor nColor, sal_uInt8 nTransparency )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) SALCOLOR_RED( nColor )) / 255,
                 ((float) SALCOLOR_GREEN( nColor )) / 255,
                 ((float) SALCOLOR_BLUE( nColor )) / 255,
                 (100 - nTransparency) * (1.0 / 100) );

    if( nTransparency > 0 )
        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

void OpenGLProgram::SetColorf( const OString& rName, SalColor nColor, double fTransparency )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) SALCOLOR_RED( nColor )) / 255,
                 ((float) SALCOLOR_GREEN( nColor )) / 255,
                 ((float) SALCOLOR_BLUE( nColor )) / 255,
                 (1.0f - fTransparency) );

    if( fTransparency > 0.0 )
        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

void OpenGLProgram::SetColor( const OString& rName, const Color& rColor )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) rColor.GetRed()) / 255,
                 ((float) rColor.GetGreen()) / 255,
                 ((float) rColor.GetBlue()) / 255,
                 1.0f - ((float) rColor.GetTransparency()) / 255 );

    if( rColor.GetTransparency() > 0 )
        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

void OpenGLProgram::SetColorWithIntensity( const OString& rName, const Color& rColor, long nFactor )
{
    GLuint nUniform = GetUniformLocation( rName );
    glUniform4f( nUniform,
                 ((float) rColor.GetRed()) * nFactor / 25500.0,
                 ((float) rColor.GetGreen()) * nFactor / 25500.0,
                 ((float) rColor.GetBlue()) * nFactor / 25500.0,
                 1.0f );
}

void OpenGLProgram::SetTexture( const OString& rName, OpenGLTexture& rTexture )
{
    GLuint nUniform = GetUniformLocation( rName );
    int nIndex = maTextures.size();

    glUniform1i( nUniform, nIndex );
    glActiveTexture( GL_TEXTURE0 + nIndex );
    rTexture.Bind();
    maTextures.push_back( rTexture );
}

void OpenGLProgram::SetTransform(
    const OString& rName,
    const OpenGLTexture& rTexture,
    const basegfx::B2DPoint& rNull,
    const basegfx::B2DPoint& rX,
    const basegfx::B2DPoint& rY )
{
    auto nTexWidth = rTexture.GetWidth();
    auto nTexHeight = rTexture.GetHeight();
    if (nTexWidth == 0 || nTexHeight == 0)
        return;

    GLuint nUniform = GetUniformLocation( rName );
    const basegfx::B2DVector aXRel = rX - rNull;
    const basegfx::B2DVector aYRel = rY - rNull;
    const float aValues[] = {
        (float) aXRel.getX()/nTexWidth,  (float) aXRel.getY()/nTexWidth,  0, 0,
        (float) aYRel.getX()/nTexHeight, (float) aYRel.getY()/nTexHeight, 0, 0,
        0,                               0,                               1, 0,
        (float) rNull.getX(),            (float) rNull.getY(),            0, 1 };
    glm::mat4 mMatrix = glm::make_mat4( aValues );
    glUniformMatrix4fv( nUniform, 1, GL_FALSE, glm::value_ptr( mMatrix ) );
}

void OpenGLProgram::SetBlendMode( GLenum nSFactor, GLenum nDFactor )
{
    glEnable( GL_BLEND );
    glBlendFunc( nSFactor, nDFactor );
    mbBlending = true;
}

bool OpenGLProgram::DrawTexture( OpenGLTexture& rTexture )
{
    GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
    GLfloat aTexCoord[8];

    if( !rTexture )
        return false;

    rTexture.GetWholeCoord( aTexCoord );
    SetVertices( aPosition );
    SetTextureCoord( aTexCoord );
    glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
    CHECK_GL_ERROR();

    return true;
}

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


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

#include "ble/Gap.h"

namespace {

ble_error_t convert_address_type(
    Gap::PeerAddressType_t input_type,
    const BLEProtocol::AddressBytes_t address,
    BLEProtocol::AddressType_t& output_type
) {
    typedef Gap::RandomAddressType_t RandomAddressType_t;
    typedef Gap::PeerAddressType_t PeerAddressType_t;
    typedef BLEProtocol::AddressType LegacyAddressType_t;

    // best effort; peerAddrTypeIn should not be used when privacy is on.
    switch(input_type.value()) {
        case PeerAddressType_t::PUBLIC:
        case PeerAddressType_t::PUBLIC_IDENTITY:
            output_type = LegacyAddressType_t::PUBLIC;
            break;
        case PeerAddressType_t::RANDOM: {
            RandomAddressType_t random_address_type(RandomAddressType_t::STATIC);
            ble_error_t err = Gap::getRandomAddressType(address, &random_address_type);
            if (err) {
                return err;
            }
            switch (random_address_type.value()) {
                case RandomAddressType_t::STATIC:
                    output_type = LegacyAddressType_t::RANDOM_STATIC;
                    break;
                case RandomAddressType_t::NON_RESOLVABLE_PRIVATE:
                    output_type = LegacyAddressType_t::RANDOM_PRIVATE_NON_RESOLVABLE;
                    break;
                case RandomAddressType_t::RESOLVABLE_PRIVATE:
                    output_type = LegacyAddressType_t::RANDOM_PRIVATE_RESOLVABLE;
                    break;
            }
            break;
        }
        case PeerAddressType_t::RANDOM_STATIC_IDENTITY:
            output_type = LegacyAddressType_t::RANDOM_STATIC;
            break;
    }

    return BLE_ERROR_NONE;
}

Gap::PeerAddressType_t convert_legacy_address_type(
    BLEProtocol::AddressType_t legacy_address
) {
    if (legacy_address == BLEProtocol::AddressType::PUBLIC) {
        return Gap::PeerAddressType_t::PUBLIC;
    } else {
        return Gap::PeerAddressType_t::RANDOM;
    }
}

}

const Gap::PeripheralPrivacyConfiguration_t Gap::default_peripheral_privacy_configuration = {
    /* use_non_resolvable_random_address */ false,
    /* resolution_strategy */ PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE
};

const Gap::CentralPrivacyConfiguration_t Gap::default_central_privacy_configuration = {
    /* use_non_resolvable_random_address */ false,
    /* resolution_strategy */ CentralPrivacyConfiguration_t::DO_NOT_RESOLVE
};

void Gap::processConnectionEvent(
    Handle_t handle,
    Role_t role,
    PeerAddressType_t peerAddrType,
    const BLEProtocol::AddressBytes_t peerAddr,
    BLEProtocol::AddressType_t ownAddrType,
    const BLEProtocol::AddressBytes_t ownAddr,
    const ConnectionParams_t *connectionParams,
    const uint8_t *peerResolvableAddr,
    const uint8_t *localResolvableAddr
) {
    /* Update Gap state */
    state.advertising = 0;
    state.connected   = 1;
    ++connectionCount;

    ConnectionCallbackParams_t callbackParams(
        handle,
        role,
        peerAddrType,
        peerAddr,
        ownAddrType,
        ownAddr,
        connectionParams,
        peerResolvableAddr,
        localResolvableAddr
    );

    connectionCallChain.call(&callbackParams);
}

void Gap::processAdvertisementReport(
    const BLEProtocol::AddressBytes_t peerAddr,
    int8_t rssi,
    bool isScanResponse,
    GapAdvertisingParams::AdvertisingType_t type,
    uint8_t advertisingDataLen,
    const uint8_t *advertisingData,
    PeerAddressType_t addressType
) {
    AdvertisementCallbackParams_t params;

    memcpy(params.peerAddr, peerAddr, ADDR_LEN);
    params.rssi = rssi;
    params.isScanResponse = isScanResponse;
    params.type = type;
    params.advertisingDataLen = advertisingDataLen;
    params.advertisingData = advertisingData;
    params.peerAddrType = addressType;

    convert_address_type(
        addressType,
        peerAddr,
        params.addressType
    );

    onAdvertisementReport.call(&params);
}

#if defined(__GNUC__) && !defined(__CC_ARM)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__CC_ARM)
#pragma push
#pragma diag_suppress 1361
#endif

Gap::AdvertisementCallbackParams_t::AdvertisementCallbackParams_t() :
    peerAddr(),
    rssi(),
    isScanResponse(),
    type(),
    advertisingDataLen(0),
    advertisingData(NULL),
    addressType(),
    peerAddrType(PeerAddressType_t::PUBLIC)
{
}

ble_error_t Gap::getRandomAddressType(
    const BLEProtocol::AddressBytes_t address,
    RandomAddressType_t* type
) {
    // see section Device address in Bluetooth Link Layer specification
    // (Vol 6 - Part B)
    switch (address[5] >> 6) {
        case 0x03:
            *type = RandomAddressType_t::STATIC;
            return BLE_ERROR_NONE;
        case 0x00:
            *type = RandomAddressType_t::NON_RESOLVABLE_PRIVATE;
            return BLE_ERROR_NONE;
        case 0x02:
            *type = RandomAddressType_t::RESOLVABLE_PRIVATE;
            return BLE_ERROR_NONE;
        default:
            return BLE_ERROR_INVALID_PARAM;
    }
}

Gap::ConnectionCallbackParams_t::ConnectionCallbackParams_t(
    Handle_t handleIn,
    Role_t roleIn,
    BLEProtocol::AddressType_t peerAddrTypeIn,
    const uint8_t *peerAddrIn,
    BLEProtocol::AddressType_t ownAddrTypeIn,
    const uint8_t *ownAddrIn,
    const ConnectionParams_t *connectionParamsIn,
    const uint8_t *peerResolvableAddrIn,
    const uint8_t *localResolvableAddrIn
) : handle(handleIn),
    role(roleIn),
    peerAddrType(peerAddrTypeIn),
    peerAddr(),
    ownAddrType(ownAddrTypeIn),
    ownAddr(),
    connectionParams(connectionParamsIn),
    peerResolvableAddr(),
    localResolvableAddr(),
    peerAddressType(convert_legacy_address_type(peerAddrTypeIn))
{
    constructor_helper(
        peerAddrIn,
        ownAddrIn,
        peerResolvableAddrIn,
        localResolvableAddrIn
    );
}

Gap::ConnectionCallbackParams_t::ConnectionCallbackParams_t(
    Handle_t handleIn,
    Role_t roleIn,
    PeerAddressType_t peerAddrTypeIn,
    const uint8_t *peerAddrIn,
    BLEProtocol::AddressType_t ownAddrTypeIn,
    const uint8_t *ownAddrIn,
    const ConnectionParams_t *connectionParamsIn,
    const uint8_t *peerResolvableAddrIn,
    const uint8_t *localResolvableAddrIn
) : handle(handleIn),
    role(roleIn),
    peerAddrType(),
    peerAddr(),
    ownAddrType(ownAddrTypeIn),
    ownAddr(),
    connectionParams(connectionParamsIn),
    peerResolvableAddr(),
    localResolvableAddr(),
    peerAddressType(peerAddrTypeIn)
{
    constructor_helper(
        peerAddrIn,
        ownAddrIn,
        peerResolvableAddrIn,
        localResolvableAddrIn
    );

    convert_address_type(peerAddrTypeIn, peerAddrIn, peerAddrType);
}

void Gap::ConnectionCallbackParams_t::constructor_helper(
    const uint8_t *peerAddrIn,
    const uint8_t *ownAddrIn,
    const uint8_t *peerResolvableAddrIn,
    const uint8_t *localResolvableAddrIn
) {
    memcpy(peerAddr, peerAddrIn, ADDR_LEN);

    if (ownAddrIn) {
        memcpy(ownAddr, ownAddrIn, ADDR_LEN);
    } else {
        memset(ownAddr, 0, ADDR_LEN);
    }

    if (peerResolvableAddrIn) {
        memcpy(peerResolvableAddr, peerResolvableAddrIn, ADDR_LEN);
    } else {
        memset(ownAddr, 0, ADDR_LEN);
    }

    if (localResolvableAddrIn) {
        memcpy(localResolvableAddr, localResolvableAddrIn, ADDR_LEN);
    } else {
        memset(ownAddr, 0, ADDR_LEN);
    }
}

ble_error_t Gap::connect(
    const BLEProtocol::AddressBytes_t peerAddr,
    DeprecatedAddressType_t peerAddrType,
    const ConnectionParams_t *connectionParams,
    const GapScanningParams *scanParams
) {
    return connect(
        peerAddr,
        (BLEProtocol::AddressType_t) peerAddrType,
        connectionParams,
        scanParams
    );
}

void Gap::processConnectionEvent(
    Handle_t handle,
    Role_t role,
    BLEProtocol::AddressType_t peerAddrType,
    const BLEProtocol::AddressBytes_t peerAddr,
    BLEProtocol::AddressType_t ownAddrType,
    const BLEProtocol::AddressBytes_t ownAddr,
    const ConnectionParams_t *connectionParams,
    const uint8_t *peerResolvableAddr,
    const uint8_t *localResolvableAddr
) {
    /* Update Gap state */
    state.advertising = 0;
    state.connected   = 1;
    ++connectionCount;

    ConnectionCallbackParams_t callbackParams(
        handle,
        role,
        peerAddrType,
        peerAddr,
        ownAddrType,
        ownAddr,
        connectionParams,
        peerResolvableAddr,
        localResolvableAddr
    );

    connectionCallChain.call(&callbackParams);
}

void Gap::processAdvertisementReport(
    const BLEProtocol::AddressBytes_t peerAddr,
    int8_t rssi,
    bool isScanResponse,
    GapAdvertisingParams::AdvertisingType_t type,
    uint8_t advertisingDataLen,
    const uint8_t *advertisingData,
    BLEProtocol::AddressType_t addressType
) {
    AdvertisementCallbackParams_t params;
    memcpy(params.peerAddr, peerAddr, ADDR_LEN);
    params.rssi = rssi;
    params.isScanResponse = isScanResponse;
    params.type = type;
    params.advertisingDataLen = advertisingDataLen;
    params.advertisingData = advertisingData;
    params.addressType = addressType;

    params.peerAddrType = convert_legacy_address_type(addressType);
    onAdvertisementReport.call(&params);
}

#if defined(__GNUC__) && !defined(__CC_ARM)
#pragma GCC diagnostic pop
#elif defined(__CC_ARM)
#pragma pop
#endif
<commit_msg>BLE: Fix resolvable private address identification.<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ble/Gap.h"

namespace {

ble_error_t convert_address_type(
    Gap::PeerAddressType_t input_type,
    const BLEProtocol::AddressBytes_t address,
    BLEProtocol::AddressType_t& output_type
) {
    typedef Gap::RandomAddressType_t RandomAddressType_t;
    typedef Gap::PeerAddressType_t PeerAddressType_t;
    typedef BLEProtocol::AddressType LegacyAddressType_t;

    // best effort; peerAddrTypeIn should not be used when privacy is on.
    switch(input_type.value()) {
        case PeerAddressType_t::PUBLIC:
        case PeerAddressType_t::PUBLIC_IDENTITY:
            output_type = LegacyAddressType_t::PUBLIC;
            break;
        case PeerAddressType_t::RANDOM: {
            RandomAddressType_t random_address_type(RandomAddressType_t::STATIC);
            ble_error_t err = Gap::getRandomAddressType(address, &random_address_type);
            if (err) {
                return err;
            }
            switch (random_address_type.value()) {
                case RandomAddressType_t::STATIC:
                    output_type = LegacyAddressType_t::RANDOM_STATIC;
                    break;
                case RandomAddressType_t::NON_RESOLVABLE_PRIVATE:
                    output_type = LegacyAddressType_t::RANDOM_PRIVATE_NON_RESOLVABLE;
                    break;
                case RandomAddressType_t::RESOLVABLE_PRIVATE:
                    output_type = LegacyAddressType_t::RANDOM_PRIVATE_RESOLVABLE;
                    break;
            }
            break;
        }
        case PeerAddressType_t::RANDOM_STATIC_IDENTITY:
            output_type = LegacyAddressType_t::RANDOM_STATIC;
            break;
    }

    return BLE_ERROR_NONE;
}

Gap::PeerAddressType_t convert_legacy_address_type(
    BLEProtocol::AddressType_t legacy_address
) {
    if (legacy_address == BLEProtocol::AddressType::PUBLIC) {
        return Gap::PeerAddressType_t::PUBLIC;
    } else {
        return Gap::PeerAddressType_t::RANDOM;
    }
}

}

const Gap::PeripheralPrivacyConfiguration_t Gap::default_peripheral_privacy_configuration = {
    /* use_non_resolvable_random_address */ false,
    /* resolution_strategy */ PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE
};

const Gap::CentralPrivacyConfiguration_t Gap::default_central_privacy_configuration = {
    /* use_non_resolvable_random_address */ false,
    /* resolution_strategy */ CentralPrivacyConfiguration_t::DO_NOT_RESOLVE
};

void Gap::processConnectionEvent(
    Handle_t handle,
    Role_t role,
    PeerAddressType_t peerAddrType,
    const BLEProtocol::AddressBytes_t peerAddr,
    BLEProtocol::AddressType_t ownAddrType,
    const BLEProtocol::AddressBytes_t ownAddr,
    const ConnectionParams_t *connectionParams,
    const uint8_t *peerResolvableAddr,
    const uint8_t *localResolvableAddr
) {
    /* Update Gap state */
    state.advertising = 0;
    state.connected   = 1;
    ++connectionCount;

    ConnectionCallbackParams_t callbackParams(
        handle,
        role,
        peerAddrType,
        peerAddr,
        ownAddrType,
        ownAddr,
        connectionParams,
        peerResolvableAddr,
        localResolvableAddr
    );

    connectionCallChain.call(&callbackParams);
}

void Gap::processAdvertisementReport(
    const BLEProtocol::AddressBytes_t peerAddr,
    int8_t rssi,
    bool isScanResponse,
    GapAdvertisingParams::AdvertisingType_t type,
    uint8_t advertisingDataLen,
    const uint8_t *advertisingData,
    PeerAddressType_t addressType
) {
    AdvertisementCallbackParams_t params;

    memcpy(params.peerAddr, peerAddr, ADDR_LEN);
    params.rssi = rssi;
    params.isScanResponse = isScanResponse;
    params.type = type;
    params.advertisingDataLen = advertisingDataLen;
    params.advertisingData = advertisingData;
    params.peerAddrType = addressType;

    convert_address_type(
        addressType,
        peerAddr,
        params.addressType
    );

    onAdvertisementReport.call(&params);
}

#if defined(__GNUC__) && !defined(__CC_ARM)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__CC_ARM)
#pragma push
#pragma diag_suppress 1361
#endif

Gap::AdvertisementCallbackParams_t::AdvertisementCallbackParams_t() :
    peerAddr(),
    rssi(),
    isScanResponse(),
    type(),
    advertisingDataLen(0),
    advertisingData(NULL),
    addressType(),
    peerAddrType(PeerAddressType_t::PUBLIC)
{
}

ble_error_t Gap::getRandomAddressType(
    const BLEProtocol::AddressBytes_t address,
    RandomAddressType_t* type
) {
    // see section Device address in Bluetooth Link Layer specification
    // (Vol 6 - Part B)
    switch (address[5] >> 6) {
        case 0x03:
            *type = RandomAddressType_t::STATIC;
            return BLE_ERROR_NONE;
        case 0x00:
            *type = RandomAddressType_t::NON_RESOLVABLE_PRIVATE;
            return BLE_ERROR_NONE;
        case 0x01:
            *type = RandomAddressType_t::RESOLVABLE_PRIVATE;
            return BLE_ERROR_NONE;
        default:
            return BLE_ERROR_INVALID_PARAM;
    }
}

Gap::ConnectionCallbackParams_t::ConnectionCallbackParams_t(
    Handle_t handleIn,
    Role_t roleIn,
    BLEProtocol::AddressType_t peerAddrTypeIn,
    const uint8_t *peerAddrIn,
    BLEProtocol::AddressType_t ownAddrTypeIn,
    const uint8_t *ownAddrIn,
    const ConnectionParams_t *connectionParamsIn,
    const uint8_t *peerResolvableAddrIn,
    const uint8_t *localResolvableAddrIn
) : handle(handleIn),
    role(roleIn),
    peerAddrType(peerAddrTypeIn),
    peerAddr(),
    ownAddrType(ownAddrTypeIn),
    ownAddr(),
    connectionParams(connectionParamsIn),
    peerResolvableAddr(),
    localResolvableAddr(),
    peerAddressType(convert_legacy_address_type(peerAddrTypeIn))
{
    constructor_helper(
        peerAddrIn,
        ownAddrIn,
        peerResolvableAddrIn,
        localResolvableAddrIn
    );
}

Gap::ConnectionCallbackParams_t::ConnectionCallbackParams_t(
    Handle_t handleIn,
    Role_t roleIn,
    PeerAddressType_t peerAddrTypeIn,
    const uint8_t *peerAddrIn,
    BLEProtocol::AddressType_t ownAddrTypeIn,
    const uint8_t *ownAddrIn,
    const ConnectionParams_t *connectionParamsIn,
    const uint8_t *peerResolvableAddrIn,
    const uint8_t *localResolvableAddrIn
) : handle(handleIn),
    role(roleIn),
    peerAddrType(),
    peerAddr(),
    ownAddrType(ownAddrTypeIn),
    ownAddr(),
    connectionParams(connectionParamsIn),
    peerResolvableAddr(),
    localResolvableAddr(),
    peerAddressType(peerAddrTypeIn)
{
    constructor_helper(
        peerAddrIn,
        ownAddrIn,
        peerResolvableAddrIn,
        localResolvableAddrIn
    );

    convert_address_type(peerAddrTypeIn, peerAddrIn, peerAddrType);
}

void Gap::ConnectionCallbackParams_t::constructor_helper(
    const uint8_t *peerAddrIn,
    const uint8_t *ownAddrIn,
    const uint8_t *peerResolvableAddrIn,
    const uint8_t *localResolvableAddrIn
) {
    memcpy(peerAddr, peerAddrIn, ADDR_LEN);

    if (ownAddrIn) {
        memcpy(ownAddr, ownAddrIn, ADDR_LEN);
    } else {
        memset(ownAddr, 0, ADDR_LEN);
    }

    if (peerResolvableAddrIn) {
        memcpy(peerResolvableAddr, peerResolvableAddrIn, ADDR_LEN);
    } else {
        memset(ownAddr, 0, ADDR_LEN);
    }

    if (localResolvableAddrIn) {
        memcpy(localResolvableAddr, localResolvableAddrIn, ADDR_LEN);
    } else {
        memset(ownAddr, 0, ADDR_LEN);
    }
}

ble_error_t Gap::connect(
    const BLEProtocol::AddressBytes_t peerAddr,
    DeprecatedAddressType_t peerAddrType,
    const ConnectionParams_t *connectionParams,
    const GapScanningParams *scanParams
) {
    return connect(
        peerAddr,
        (BLEProtocol::AddressType_t) peerAddrType,
        connectionParams,
        scanParams
    );
}

void Gap::processConnectionEvent(
    Handle_t handle,
    Role_t role,
    BLEProtocol::AddressType_t peerAddrType,
    const BLEProtocol::AddressBytes_t peerAddr,
    BLEProtocol::AddressType_t ownAddrType,
    const BLEProtocol::AddressBytes_t ownAddr,
    const ConnectionParams_t *connectionParams,
    const uint8_t *peerResolvableAddr,
    const uint8_t *localResolvableAddr
) {
    /* Update Gap state */
    state.advertising = 0;
    state.connected   = 1;
    ++connectionCount;

    ConnectionCallbackParams_t callbackParams(
        handle,
        role,
        peerAddrType,
        peerAddr,
        ownAddrType,
        ownAddr,
        connectionParams,
        peerResolvableAddr,
        localResolvableAddr
    );

    connectionCallChain.call(&callbackParams);
}

void Gap::processAdvertisementReport(
    const BLEProtocol::AddressBytes_t peerAddr,
    int8_t rssi,
    bool isScanResponse,
    GapAdvertisingParams::AdvertisingType_t type,
    uint8_t advertisingDataLen,
    const uint8_t *advertisingData,
    BLEProtocol::AddressType_t addressType
) {
    AdvertisementCallbackParams_t params;
    memcpy(params.peerAddr, peerAddr, ADDR_LEN);
    params.rssi = rssi;
    params.isScanResponse = isScanResponse;
    params.type = type;
    params.advertisingDataLen = advertisingDataLen;
    params.advertisingData = advertisingData;
    params.addressType = addressType;

    params.peerAddrType = convert_legacy_address_type(addressType);
    onAdvertisementReport.call(&params);
}

#if defined(__GNUC__) && !defined(__CC_ARM)
#pragma GCC diagnostic pop
#elif defined(__CC_ARM)
#pragma pop
#endif
<|endoftext|>


<commit_before><commit_msg>Control: fix return status for mpc controller submodule<commit_after><|endoftext|>