<commit_before>//===--- TypeCheckPropertyDelegate.cpp - Property Delegates ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for property delegates.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "TypeCheckType.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/PropertyDelegates.h"
#include "swift/AST/TypeCheckRequests.h"
using namespace swift;

/// Find the named property in a property delegate to which access will
/// be delegated.
static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal,
                                  Identifier name, bool allowMissing) {
  SmallVector<VarDecl *, 2> vars;
  {
    SmallVector<ValueDecl *, 2> decls;
    nominal->lookupQualified(nominal, name, NL_QualifiedDefault, decls);
    for (const auto &foundDecl : decls) {
      auto foundVar = dyn_cast<VarDecl>(foundDecl);
      if (!foundVar || foundVar->isStatic() ||
          foundVar->getDeclContext() != nominal)
        continue;

      vars.push_back(foundVar);
    }
  }

  // Diagnose missing or ambiguous properties.
  switch (vars.size()) {
  case 0:
    if (!allowMissing) {
      nominal->diagnose(diag::property_delegate_no_value_property,
                        nominal->getDeclaredType(), name);
    }
    return nullptr;

  case 1:
    break;

  default:
    nominal->diagnose(diag::property_delegate_ambiguous_value_property,
                      nominal->getDeclaredType(), name);
    for (auto var : vars) {
      var->diagnose(diag::kind_declname_declared_here,
                    var->getDescriptiveKind(), var->getFullName());
    }
    return nullptr;
  }

  // The property must be as accessible as the nominal type.
  VarDecl *var = vars.front();
  if (var->getFormalAccess() < nominal->getFormalAccess()) {
    var->diagnose(diag::property_delegate_type_requirement_not_accessible,
                  var->getFormalAccess(), var->getDescriptiveKind(),
                  var->getFullName(), nominal->getDeclaredType(),
                  nominal->getFormalAccess());
    return nullptr;
  }

  return var;
}

/// Determine whether we have a suitable init(initialValue:) within a property
/// delegate type.
static ConstructorDecl *findInitialValueInit(ASTContext &ctx,
                                             NominalTypeDecl *nominal,
                                             VarDecl *valueVar) {
  SmallVector<ConstructorDecl *, 2> initialValueInitializers;
  DeclName initName(ctx, DeclBaseName::createConstructor(),
                    {ctx.Id_initialValue});
  SmallVector<ValueDecl *, 2> decls;
  nominal->lookupQualified(nominal, initName, NL_QualifiedDefault, decls);
  for (const auto &decl : decls) {
    auto init = dyn_cast<ConstructorDecl>(decl);
    if (!init || init->getDeclContext() != nominal)
      continue;

    initialValueInitializers.push_back(init);
  }

  switch (initialValueInitializers.size()) {
  case 0:
    return nullptr;

  case 1:
    break;

  default:
    // Diagnose ambiguous init(initialValue:) initializers.
    nominal->diagnose(diag::property_delegate_ambiguous_initial_value_init,
                      nominal->getDeclaredType());
    for (auto init : initialValueInitializers) {
      init->diagnose(diag::kind_declname_declared_here,
                     init->getDescriptiveKind(), init->getFullName());
    }
    return nullptr;
  }

  // 'init(initialValue:)' must be as accessible as the nominal type.
  auto init = initialValueInitializers.front();
  if (init->getFormalAccess() < nominal->getFormalAccess()) {
    init->diagnose(diag::property_delegate_type_requirement_not_accessible,
                     init->getFormalAccess(), init->getDescriptiveKind(),
                     init->getFullName(), nominal->getDeclaredType(),
                     nominal->getFormalAccess());
    return nullptr;
  }

  // Retrieve the type of the 'value' property.
  if (!valueVar->hasInterfaceType())
    ctx.getLazyResolver()->resolveDeclSignature(valueVar);
  Type valueVarType = valueVar->getValueInterfaceType();

  // Retrieve the parameter type of the initializer.
  if (!init->hasInterfaceType())
    ctx.getLazyResolver()->resolveDeclSignature(init);
  Type paramType;
  if (auto *curriedInitType =
          init->getInterfaceType()->getAs<AnyFunctionType>()) {
    if (auto *initType =
          curriedInitType->getResult()->getAs<AnyFunctionType>()) {
      if (initType->getParams().size() == 1) {
        const auto &param = initType->getParams()[0];
        if (!param.isInOut() && !param.isVariadic()) {
          paramType = param.getPlainType();
          if (param.isAutoClosure()) {
            if (auto *fnType = paramType->getAs<FunctionType>())
              paramType = fnType->getResult();
          }
        }
      }
    }
  }

  // The parameter type must be the same as the type of `valueVar` or an
  // autoclosure thereof.
  if (!paramType->isEqual(valueVarType)) {
    init->diagnose(diag::property_delegate_wrong_initial_value_init, paramType,
                   valueVarType);
    valueVar->diagnose(diag::decl_declared_here, valueVar->getFullName());
    return nullptr;
  }

  // The initializer must not be failable.
  if (init->getFailability() != OTK_None) {
    init->diagnose(diag::property_delegate_failable_init, initName);
    return nullptr;
  }

  return init;
}

/// Determine whether we have a suitable init() within a property
/// delegate type.
static ConstructorDecl *findDefaultInit(ASTContext &ctx,
                                        NominalTypeDecl *nominal) {
  SmallVector<ConstructorDecl *, 2> defaultValueInitializers;
  DeclName initName(ctx, DeclBaseName::createConstructor(),
                    ArrayRef<Identifier>());
  SmallVector<ValueDecl *, 2> decls;
  nominal->lookupQualified(nominal, initName, NL_QualifiedDefault, decls);
  for (const auto &decl : decls) {
    auto init = dyn_cast<ConstructorDecl>(decl);
    if (!init || init->getDeclContext() != nominal)
      continue;

    defaultValueInitializers.push_back(init);
  }

  switch (defaultValueInitializers.size()) {
  case 0:
    return nullptr;

  case 1:
    break;

  default:
    // Diagnose ambiguous init() initializers.
    nominal->diagnose(diag::property_delegate_ambiguous_default_value_init,
                      nominal->getDeclaredType());
    for (auto init : defaultValueInitializers) {
      init->diagnose(diag::kind_declname_declared_here,
                     init->getDescriptiveKind(), init->getFullName());
    }
    return nullptr;
  }

  // 'init()' must be as accessible as the nominal type.
  auto init = defaultValueInitializers.front();
  if (init->getFormalAccess() < nominal->getFormalAccess()) {
    init->diagnose(diag::property_delegate_type_requirement_not_accessible,
                     init->getFormalAccess(), init->getDescriptiveKind(),
                     init->getFullName(), nominal->getDeclaredType(),
                     nominal->getFormalAccess());
    return nullptr;
  }

  // The initializer must not be failable.
  if (init->getFailability() != OTK_None) {
    init->diagnose(diag::property_delegate_failable_init, initName);
    return nullptr;
  }

  return init;
}

llvm::Expected<PropertyDelegateTypeInfo>
PropertyDelegateTypeInfoRequest::evaluate(
    Evaluator &eval, NominalTypeDecl *nominal) const {
  // We must have the @_propertyDelegate attribute to continue.
  if (!nominal->getAttrs().hasAttribute<PropertyDelegateAttr>()) {
    return PropertyDelegateTypeInfo();
  }

  // Look for a non-static property named "value" in the property delegate
  // type.
  ASTContext &ctx = nominal->getASTContext();
  auto valueVar =
      findValueProperty(ctx, nominal, ctx.Id_value, /*allowMissing=*/false);
  if (!valueVar)
    return PropertyDelegateTypeInfo();

  PropertyDelegateTypeInfo result;
  result.valueVar = valueVar;
  result.initialValueInit = findInitialValueInit(ctx, nominal, valueVar);
  result.defaultInit = findDefaultInit(ctx, nominal);
  result.delegateValueVar =
    findValueProperty(ctx, nominal, ctx.Id_delegateValue, /*allowMissing=*/true);

  return result;
}

llvm::Expected<CustomAttr *>
AttachedPropertyDelegateRequest::evaluate(Evaluator &evaluator,
                                          VarDecl *var) const {
  ASTContext &ctx = var->getASTContext();
  auto dc = var->getDeclContext();
  for (auto attr : var->getAttrs().getAttributes<CustomAttr>()) {
    auto mutableAttr = const_cast<CustomAttr *>(attr);
    // Figure out which nominal declaration this custom attribute refers to.
    auto nominal = evaluateOrDefault(
      ctx.evaluator, CustomAttrNominalRequest{mutableAttr, dc}, nullptr);

    // If we didn't find a nominal type with a @_propertyDelegate attribute,
    // skip this custom attribute.
    if (!nominal || !nominal->getAttrs().hasAttribute<PropertyDelegateAttr>())
      continue;

    // If the declaration came from a module file, we've already done all of
    // the semantic checking required.
    if (!dc->getParentSourceFile())
      return mutableAttr;

    // Check various restrictions on which properties can have delegates
    // attached to them.

    // Local properties do not yet support delegates.
    if (var->getDeclContext()->isLocalContext()) {
      ctx.Diags.diagnose(attr->getLocation(), diag::property_delegate_local);
      return nullptr;
    }

    // Check that the variable is part of a single-variable pattern.
    auto binding = var->getParentPatternBinding();
    if (!binding || binding->getSingleVar() != var) {
      ctx.Diags.diagnose(attr->getLocation(),
                         diag::property_delegate_not_single_var);
      return nullptr;
    }

    // A property delegate cannot be attached to a 'let'.
    if (var->isLet()) {
      ctx.Diags.diagnose(attr->getLocation(), diag::property_delegate_let);
      return nullptr;
    }

    // Check for conflicting attributes.
    if (var->getAttrs().hasAttribute<LazyAttr>() ||
        var->getAttrs().hasAttribute<NSCopyingAttr>() ||
        var->getAttrs().hasAttribute<NSManagedAttr>() ||
        (var->getAttrs().hasAttribute<ReferenceOwnershipAttr>() &&
         var->getAttrs().getAttribute<ReferenceOwnershipAttr>()->get() !=
             ReferenceOwnership::Strong)) {
      int whichKind;
      if (var->getAttrs().hasAttribute<LazyAttr>())
        whichKind = 0;
      else if (var->getAttrs().hasAttribute<NSCopyingAttr>())
        whichKind = 1;
      else if (var->getAttrs().hasAttribute<NSManagedAttr>())
        whichKind = 2;
      else {
        auto attr = var->getAttrs().getAttribute<ReferenceOwnershipAttr>();
        whichKind = 2 + static_cast<unsigned>(attr->get());
      }
      var->diagnose(diag::property_with_delegate_conflict_attribute,
                    var->getFullName(), whichKind);
      return nullptr;
    }

    // A property with a delegate cannot be declared in a protocol, enum, or
    // an extension.
    if (isa<ProtocolDecl>(dc) ||
        (isa<ExtensionDecl>(dc) && var->isInstanceMember()) ||
        (isa<EnumDecl>(dc) && var->isInstanceMember())) {
      int whichKind;
      if (isa<ProtocolDecl>(dc))
        whichKind = 0;
      else if (isa<ExtensionDecl>(dc))
        whichKind = 1;
      else
        whichKind = 2;
      var->diagnose(diag::property_with_delegate_in_bad_context,
                    var->getFullName(), whichKind)
        .highlight(attr->getRange());

      return nullptr;
    }

    // Properties with delegates must not override another property.
    if (auto classDecl = dyn_cast<ClassDecl>(dc)) {
      if (auto overrideAttr = var->getAttrs().getAttribute<OverrideAttr>()) {
        var->diagnose(diag::property_with_delegate_overrides,
                      var->getFullName())
          .highlight(attr->getRange());
        return nullptr;
      }
    }

    // Properties with delegates must not declare a getter or setter.
    if (!var->hasStorage()) {
      ctx.Diags.diagnose(attr->getLocation(), diag::property_delegate_computed);
      return nullptr;
    }

    return mutableAttr;
  }

  return nullptr;
}

llvm::Expected<Type>
AttachedPropertyDelegateTypeRequest::evaluate(Evaluator &evaluator,
                                              VarDecl *var) const {
  // Find the custom attribute for the attached property delegate.
  llvm::Expected<CustomAttr *> customAttrVal =
      evaluator(AttachedPropertyDelegateRequest{var});
  if (!customAttrVal)
    return customAttrVal.takeError();

  // If there isn't an attached property delegate, we're done.
  auto customAttr = *customAttrVal;
  if (!customAttr)
    return Type();

  auto resolution =
      TypeResolution::forContextual(var->getDeclContext());
  TypeResolutionOptions options(TypeResolverContext::PatternBindingDecl);
  options |= TypeResolutionFlags::AllowUnboundGenerics;

  ASTContext &ctx = var->getASTContext();
  auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
  if (tc.validateType(customAttr->getTypeLoc(), resolution, options))
    return ErrorType::get(ctx);

  Type customAttrType = customAttr->getTypeLoc().getType();
  if (!customAttrType->getAnyNominal()) {
    assert(ctx.Diags.hadAnyError());
    return ErrorType::get(ctx);
  }

  return customAttrType;
}

llvm::Expected<Type>
PropertyDelegateBackingPropertyTypeRequest::evaluate(
                                    Evaluator &evaluator, VarDecl *var) const {
  llvm::Expected<Type> rawTypeResult =
    evaluator(AttachedPropertyDelegateTypeRequest{var});
  if (!rawTypeResult)
    return rawTypeResult;

  Type rawType = *rawTypeResult;
  if (!rawType)
    return Type();

  if (!rawType->hasUnboundGenericType())
    return rawType->mapTypeOutOfContext();

  auto binding = var->getParentPatternBinding();
  if (!binding)
    return Type();

  // If there's an initializer of some sort, checking it will determine the
  // property delegate type.
  unsigned index = binding->getPatternEntryIndexForVarDecl(var);
  ASTContext &ctx = var->getASTContext();
  TypeChecker &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
  if (binding->isInitialized(index)) {
    tc.validateDecl(var);
    if (!binding->isInitializerChecked(index))
      tc.typeCheckPatternBinding(binding, index);

    Type type = ctx.getSideCachedPropertyDelegateBackingPropertyType(var);
    assert(type || ctx.Diags.hadAnyError());
    return type;
  }

  // Compose the type of property delegate with the type of the property.

  // We expect an unbound generic type here that refers to a single-parameter
  // generic type.
  auto delegateAttr = var->getAttachedPropertyDelegate();
  auto nominal = rawType->getAnyNominal();
  auto unboundGeneric = rawType->getAs<UnboundGenericType>();
  if (!unboundGeneric ||
      unboundGeneric->getDecl() != nominal ||
      !nominal->getGenericParams() ||
      nominal->getGenericParams()->size() != 1) {
    ctx.Diags.diagnose(delegateAttr->getLocation(),
                       diag::property_delegate_incompatible_unbound,
                       rawType)
      .highlight(delegateAttr->getTypeLoc().getSourceRange());
    return Type();
  }

  // Compute the type of the property to plug in to the delegate type.
  tc.validateDecl(var);
  Type propertyType = var->getType();

  // Form the specialized type.
  Type delegateType = tc.applyUnboundGenericArguments(
      unboundGeneric, nominal, delegateAttr->getLocation(),
      TypeResolution::forContextual(var->getDeclContext()), { propertyType });

  // Make sure no unbound types remain; this could happen if there are outer
  // unbound types that weren't resolved by the application of the property
  // type.
  if (delegateType->hasUnboundGenericType()) {
    ctx.Diags.diagnose(delegateAttr->getLocation(),
                       diag::property_delegate_incompatible_unbound,
                       delegateType)
      .highlight(delegateAttr->getTypeLoc().getSourceRange());
    return Type();
  }

  return delegateType->mapTypeOutOfContext();
}
<commit_msg>[SE-0258] Swift interface files have explicit get/set for wrapped properties<commit_after>//===--- TypeCheckPropertyDelegate.cpp - Property Delegates ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for property delegates.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "TypeCheckType.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/PropertyDelegates.h"
#include "swift/AST/TypeCheckRequests.h"
using namespace swift;

/// Find the named property in a property delegate to which access will
/// be delegated.
static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal,
                                  Identifier name, bool allowMissing) {
  SmallVector<VarDecl *, 2> vars;
  {
    SmallVector<ValueDecl *, 2> decls;
    nominal->lookupQualified(nominal, name, NL_QualifiedDefault, decls);
    for (const auto &foundDecl : decls) {
      auto foundVar = dyn_cast<VarDecl>(foundDecl);
      if (!foundVar || foundVar->isStatic() ||
          foundVar->getDeclContext() != nominal)
        continue;

      vars.push_back(foundVar);
    }
  }

  // Diagnose missing or ambiguous properties.
  switch (vars.size()) {
  case 0:
    if (!allowMissing) {
      nominal->diagnose(diag::property_delegate_no_value_property,
                        nominal->getDeclaredType(), name);
    }
    return nullptr;

  case 1:
    break;

  default:
    nominal->diagnose(diag::property_delegate_ambiguous_value_property,
                      nominal->getDeclaredType(), name);
    for (auto var : vars) {
      var->diagnose(diag::kind_declname_declared_here,
                    var->getDescriptiveKind(), var->getFullName());
    }
    return nullptr;
  }

  // The property must be as accessible as the nominal type.
  VarDecl *var = vars.front();
  if (var->getFormalAccess() < nominal->getFormalAccess()) {
    var->diagnose(diag::property_delegate_type_requirement_not_accessible,
                  var->getFormalAccess(), var->getDescriptiveKind(),
                  var->getFullName(), nominal->getDeclaredType(),
                  nominal->getFormalAccess());
    return nullptr;
  }

  return var;
}

/// Determine whether we have a suitable init(initialValue:) within a property
/// delegate type.
static ConstructorDecl *findInitialValueInit(ASTContext &ctx,
                                             NominalTypeDecl *nominal,
                                             VarDecl *valueVar) {
  SmallVector<ConstructorDecl *, 2> initialValueInitializers;
  DeclName initName(ctx, DeclBaseName::createConstructor(),
                    {ctx.Id_initialValue});
  SmallVector<ValueDecl *, 2> decls;
  nominal->lookupQualified(nominal, initName, NL_QualifiedDefault, decls);
  for (const auto &decl : decls) {
    auto init = dyn_cast<ConstructorDecl>(decl);
    if (!init || init->getDeclContext() != nominal)
      continue;

    initialValueInitializers.push_back(init);
  }

  switch (initialValueInitializers.size()) {
  case 0:
    return nullptr;

  case 1:
    break;

  default:
    // Diagnose ambiguous init(initialValue:) initializers.
    nominal->diagnose(diag::property_delegate_ambiguous_initial_value_init,
                      nominal->getDeclaredType());
    for (auto init : initialValueInitializers) {
      init->diagnose(diag::kind_declname_declared_here,
                     init->getDescriptiveKind(), init->getFullName());
    }
    return nullptr;
  }

  // 'init(initialValue:)' must be as accessible as the nominal type.
  auto init = initialValueInitializers.front();
  if (init->getFormalAccess() < nominal->getFormalAccess()) {
    init->diagnose(diag::property_delegate_type_requirement_not_accessible,
                     init->getFormalAccess(), init->getDescriptiveKind(),
                     init->getFullName(), nominal->getDeclaredType(),
                     nominal->getFormalAccess());
    return nullptr;
  }

  // Retrieve the type of the 'value' property.
  if (!valueVar->hasInterfaceType())
    ctx.getLazyResolver()->resolveDeclSignature(valueVar);
  Type valueVarType = valueVar->getValueInterfaceType();

  // Retrieve the parameter type of the initializer.
  if (!init->hasInterfaceType())
    ctx.getLazyResolver()->resolveDeclSignature(init);
  Type paramType;
  if (auto *curriedInitType =
          init->getInterfaceType()->getAs<AnyFunctionType>()) {
    if (auto *initType =
          curriedInitType->getResult()->getAs<AnyFunctionType>()) {
      if (initType->getParams().size() == 1) {
        const auto &param = initType->getParams()[0];
        if (!param.isInOut() && !param.isVariadic()) {
          paramType = param.getPlainType();
          if (param.isAutoClosure()) {
            if (auto *fnType = paramType->getAs<FunctionType>())
              paramType = fnType->getResult();
          }
        }
      }
    }
  }

  // The parameter type must be the same as the type of `valueVar` or an
  // autoclosure thereof.
  if (!paramType->isEqual(valueVarType)) {
    init->diagnose(diag::property_delegate_wrong_initial_value_init, paramType,
                   valueVarType);
    valueVar->diagnose(diag::decl_declared_here, valueVar->getFullName());
    return nullptr;
  }

  // The initializer must not be failable.
  if (init->getFailability() != OTK_None) {
    init->diagnose(diag::property_delegate_failable_init, initName);
    return nullptr;
  }

  return init;
}

/// Determine whether we have a suitable init() within a property
/// delegate type.
static ConstructorDecl *findDefaultInit(ASTContext &ctx,
                                        NominalTypeDecl *nominal) {
  SmallVector<ConstructorDecl *, 2> defaultValueInitializers;
  DeclName initName(ctx, DeclBaseName::createConstructor(),
                    ArrayRef<Identifier>());
  SmallVector<ValueDecl *, 2> decls;
  nominal->lookupQualified(nominal, initName, NL_QualifiedDefault, decls);
  for (const auto &decl : decls) {
    auto init = dyn_cast<ConstructorDecl>(decl);
    if (!init || init->getDeclContext() != nominal)
      continue;

    defaultValueInitializers.push_back(init);
  }

  switch (defaultValueInitializers.size()) {
  case 0:
    return nullptr;

  case 1:
    break;

  default:
    // Diagnose ambiguous init() initializers.
    nominal->diagnose(diag::property_delegate_ambiguous_default_value_init,
                      nominal->getDeclaredType());
    for (auto init : defaultValueInitializers) {
      init->diagnose(diag::kind_declname_declared_here,
                     init->getDescriptiveKind(), init->getFullName());
    }
    return nullptr;
  }

  // 'init()' must be as accessible as the nominal type.
  auto init = defaultValueInitializers.front();
  if (init->getFormalAccess() < nominal->getFormalAccess()) {
    init->diagnose(diag::property_delegate_type_requirement_not_accessible,
                     init->getFormalAccess(), init->getDescriptiveKind(),
                     init->getFullName(), nominal->getDeclaredType(),
                     nominal->getFormalAccess());
    return nullptr;
  }

  // The initializer must not be failable.
  if (init->getFailability() != OTK_None) {
    init->diagnose(diag::property_delegate_failable_init, initName);
    return nullptr;
  }

  return init;
}

llvm::Expected<PropertyDelegateTypeInfo>
PropertyDelegateTypeInfoRequest::evaluate(
    Evaluator &eval, NominalTypeDecl *nominal) const {
  // We must have the @_propertyDelegate attribute to continue.
  if (!nominal->getAttrs().hasAttribute<PropertyDelegateAttr>()) {
    return PropertyDelegateTypeInfo();
  }

  // Look for a non-static property named "value" in the property delegate
  // type.
  ASTContext &ctx = nominal->getASTContext();
  auto valueVar =
      findValueProperty(ctx, nominal, ctx.Id_value, /*allowMissing=*/false);
  if (!valueVar)
    return PropertyDelegateTypeInfo();

  PropertyDelegateTypeInfo result;
  result.valueVar = valueVar;
  result.initialValueInit = findInitialValueInit(ctx, nominal, valueVar);
  result.defaultInit = findDefaultInit(ctx, nominal);
  result.delegateValueVar =
    findValueProperty(ctx, nominal, ctx.Id_delegateValue, /*allowMissing=*/true);

  return result;
}

llvm::Expected<CustomAttr *>
AttachedPropertyDelegateRequest::evaluate(Evaluator &evaluator,
                                          VarDecl *var) const {
  ASTContext &ctx = var->getASTContext();
  auto dc = var->getDeclContext();
  for (auto attr : var->getAttrs().getAttributes<CustomAttr>()) {
    auto mutableAttr = const_cast<CustomAttr *>(attr);
    // Figure out which nominal declaration this custom attribute refers to.
    auto nominal = evaluateOrDefault(
      ctx.evaluator, CustomAttrNominalRequest{mutableAttr, dc}, nullptr);

    // If we didn't find a nominal type with a @_propertyDelegate attribute,
    // skip this custom attribute.
    if (!nominal || !nominal->getAttrs().hasAttribute<PropertyDelegateAttr>())
      continue;

    // If the declaration came from a module file, we've already done all of
    // the semantic checking required.
    auto sourceFile = dc->getParentSourceFile();
    if (!sourceFile)
      return mutableAttr;

    // Check various restrictions on which properties can have delegates
    // attached to them.

    // Local properties do not yet support delegates.
    if (var->getDeclContext()->isLocalContext()) {
      ctx.Diags.diagnose(attr->getLocation(), diag::property_delegate_local);
      return nullptr;
    }

    // Check that the variable is part of a single-variable pattern.
    auto binding = var->getParentPatternBinding();
    if (!binding || binding->getSingleVar() != var) {
      ctx.Diags.diagnose(attr->getLocation(),
                         diag::property_delegate_not_single_var);
      return nullptr;
    }

    // A property delegate cannot be attached to a 'let'.
    if (var->isLet()) {
      ctx.Diags.diagnose(attr->getLocation(), diag::property_delegate_let);
      return nullptr;
    }

    // Check for conflicting attributes.
    if (var->getAttrs().hasAttribute<LazyAttr>() ||
        var->getAttrs().hasAttribute<NSCopyingAttr>() ||
        var->getAttrs().hasAttribute<NSManagedAttr>() ||
        (var->getAttrs().hasAttribute<ReferenceOwnershipAttr>() &&
         var->getAttrs().getAttribute<ReferenceOwnershipAttr>()->get() !=
             ReferenceOwnership::Strong)) {
      int whichKind;
      if (var->getAttrs().hasAttribute<LazyAttr>())
        whichKind = 0;
      else if (var->getAttrs().hasAttribute<NSCopyingAttr>())
        whichKind = 1;
      else if (var->getAttrs().hasAttribute<NSManagedAttr>())
        whichKind = 2;
      else {
        auto attr = var->getAttrs().getAttribute<ReferenceOwnershipAttr>();
        whichKind = 2 + static_cast<unsigned>(attr->get());
      }
      var->diagnose(diag::property_with_delegate_conflict_attribute,
                    var->getFullName(), whichKind);
      return nullptr;
    }

    // A property with a delegate cannot be declared in a protocol, enum, or
    // an extension.
    if (isa<ProtocolDecl>(dc) ||
        (isa<ExtensionDecl>(dc) && var->isInstanceMember()) ||
        (isa<EnumDecl>(dc) && var->isInstanceMember())) {
      int whichKind;
      if (isa<ProtocolDecl>(dc))
        whichKind = 0;
      else if (isa<ExtensionDecl>(dc))
        whichKind = 1;
      else
        whichKind = 2;
      var->diagnose(diag::property_with_delegate_in_bad_context,
                    var->getFullName(), whichKind)
        .highlight(attr->getRange());

      return nullptr;
    }

    // Properties with delegates must not override another property.
    if (auto classDecl = dyn_cast<ClassDecl>(dc)) {
      if (auto overrideAttr = var->getAttrs().getAttribute<OverrideAttr>()) {
        var->diagnose(diag::property_with_delegate_overrides,
                      var->getFullName())
          .highlight(attr->getRange());
        return nullptr;
      }
    }

    // Properties with delegates must not declare a getter or setter.
    if (!var->hasStorage() && sourceFile->Kind != SourceFileKind::Interface) {
      ctx.Diags.diagnose(attr->getLocation(), diag::property_delegate_computed);
      return nullptr;
    }

    return mutableAttr;
  }

  return nullptr;
}

llvm::Expected<Type>
AttachedPropertyDelegateTypeRequest::evaluate(Evaluator &evaluator,
                                              VarDecl *var) const {
  // Find the custom attribute for the attached property delegate.
  llvm::Expected<CustomAttr *> customAttrVal =
      evaluator(AttachedPropertyDelegateRequest{var});
  if (!customAttrVal)
    return customAttrVal.takeError();

  // If there isn't an attached property delegate, we're done.
  auto customAttr = *customAttrVal;
  if (!customAttr)
    return Type();

  auto resolution =
      TypeResolution::forContextual(var->getDeclContext());
  TypeResolutionOptions options(TypeResolverContext::PatternBindingDecl);
  options |= TypeResolutionFlags::AllowUnboundGenerics;

  ASTContext &ctx = var->getASTContext();
  auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
  if (tc.validateType(customAttr->getTypeLoc(), resolution, options))
    return ErrorType::get(ctx);

  Type customAttrType = customAttr->getTypeLoc().getType();
  if (!customAttrType->getAnyNominal()) {
    assert(ctx.Diags.hadAnyError());
    return ErrorType::get(ctx);
  }

  return customAttrType;
}

llvm::Expected<Type>
PropertyDelegateBackingPropertyTypeRequest::evaluate(
                                    Evaluator &evaluator, VarDecl *var) const {
  llvm::Expected<Type> rawTypeResult =
    evaluator(AttachedPropertyDelegateTypeRequest{var});
  if (!rawTypeResult)
    return rawTypeResult;

  Type rawType = *rawTypeResult;
  if (!rawType)
    return Type();

  if (!rawType->hasUnboundGenericType())
    return rawType->mapTypeOutOfContext();

  auto binding = var->getParentPatternBinding();
  if (!binding)
    return Type();

  // If there's an initializer of some sort, checking it will determine the
  // property delegate type.
  unsigned index = binding->getPatternEntryIndexForVarDecl(var);
  ASTContext &ctx = var->getASTContext();
  TypeChecker &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
  if (binding->isInitialized(index)) {
    tc.validateDecl(var);
    if (!binding->isInitializerChecked(index))
      tc.typeCheckPatternBinding(binding, index);

    Type type = ctx.getSideCachedPropertyDelegateBackingPropertyType(var);
    assert(type || ctx.Diags.hadAnyError());
    return type;
  }

  // Compose the type of property delegate with the type of the property.

  // We expect an unbound generic type here that refers to a single-parameter
  // generic type.
  auto delegateAttr = var->getAttachedPropertyDelegate();
  auto nominal = rawType->getAnyNominal();
  auto unboundGeneric = rawType->getAs<UnboundGenericType>();
  if (!unboundGeneric ||
      unboundGeneric->getDecl() != nominal ||
      !nominal->getGenericParams() ||
      nominal->getGenericParams()->size() != 1) {
    ctx.Diags.diagnose(delegateAttr->getLocation(),
                       diag::property_delegate_incompatible_unbound,
                       rawType)
      .highlight(delegateAttr->getTypeLoc().getSourceRange());
    return Type();
  }

  // Compute the type of the property to plug in to the delegate type.
  tc.validateDecl(var);
  Type propertyType = var->getType();

  // Form the specialized type.
  Type delegateType = tc.applyUnboundGenericArguments(
      unboundGeneric, nominal, delegateAttr->getLocation(),
      TypeResolution::forContextual(var->getDeclContext()), { propertyType });

  // Make sure no unbound types remain; this could happen if there are outer
  // unbound types that weren't resolved by the application of the property
  // type.
  if (delegateType->hasUnboundGenericType()) {
    ctx.Diags.diagnose(delegateAttr->getLocation(),
                       diag::property_delegate_incompatible_unbound,
                       delegateType)
      .highlight(delegateAttr->getTypeLoc().getSourceRange());
    return Type();
  }

  return delegateType->mapTypeOutOfContext();
}
<|endoftext|>


<commit_before>#include "gui/window.hpp"

#include <SFML/Graphics/RenderTarget.hpp>

namespace qrw
{
	Window::Window()
	{
	}

	Window::~Window()
	{
	}

	void Window::setVisible(bool visible)
	{
		this->visible = visible;
		for(std::vector<Widget*>::iterator iter = children.begin(); iter != children.end(); ++iter)
		{
			(*iter)->setVisible(visible);
		}
	}

	bool Window::isVisible()
	{
		return visible;
	}

	void Window::addWidget(Widget* widget)
	{
		children.push_back(widget);
	}

	void Window::draw(sf::RenderTarget& target, sf::RenderStates states) const
	{
		if(!visible)
			return;

		for(auto iter = children.begin(); iter != children.end(); ++iter)
			target.draw(*(*iter), states);
	}

	void Window::handleEvent(const sf::Event& event)
	{
		if(visible)
		{
			for(auto iter = children.begin(); iter != children.end(); ++iter)
				(*iter)->handleEvent(event);
		}
	}
}<commit_msg>Improved code readability in Window::draw().<commit_after>#include "gui/window.hpp"

#include <SFML/Graphics/RenderTarget.hpp>

namespace qrw
{
	Window::Window()
	{
	}

	Window::~Window()
	{
	}

	void Window::setVisible(bool visible)
	{
		this->visible = visible;
		for(std::vector<Widget*>::iterator iter = children.begin(); iter != children.end(); ++iter)
		{
			(*iter)->setVisible(visible);
		}
	}

	bool Window::isVisible()
	{
		return visible;
	}

	void Window::addWidget(Widget* widget)
	{
		children.push_back(widget);
	}

	void Window::draw(sf::RenderTarget& target, sf::RenderStates states) const
	{
		if(visible)
		{
			for(auto iter = children.begin(); iter != children.end(); ++iter)
				target.draw(*(*iter), states);
		}
	}

	void Window::handleEvent(const sf::Event& event)
	{
		if(visible)
		{
			for(auto iter = children.begin(); iter != children.end(); ++iter)
				(*iter)->handleEvent(event);
		}
	}
}<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>

#include "os/task_t.h"
#include "os/task_system_t.h"
#include "os/parse.h"
#include "lib/io.h"

int main(){
	std::cout << "Hello world!" << std::endl;

	{
		os::task_t task;
		std::cout << task << std::endl;
	}

	{
		os::task_system_t task_system(5);
		std::cout << task_system << std::endl;
	}

	{
		std::ifstream ifs("system/0", std::ifstream::in);
		char c = ifs.get();
		while (ifs.good()){
			std::cout << c;
			c = ifs.get();
		}
		ifs.close();
		std::cout << '\n';
	}

	{
		os::task_system_t task_system;
		std::cout << task_system << std::endl;

		std::ifstream ifs("system/0", std::ifstream::in);
		os::parse_task_system_stream(ifs, task_system);
		ifs.close();

		std::cout << task_system << std::endl;
	}
	return 0;
}<commit_msg>include generator (no syntax error)<commit_after>#include <iostream>
#include <fstream>

#include "os/task_t.h"
#include "os/task_system_t.h"
#include "os/parse.h"
#include "os/generator.h"
#include "lib/io.h"

int main(){
	std::cout << "Hello world!" << std::endl;

	{
		os::task_t task;
		std::cout << task << std::endl;
	}

	{
		os::task_system_t task_system(5);
		std::cout << task_system << std::endl;
	}

	{
		std::ifstream ifs("system/0", std::ifstream::in);
		char c = ifs.get();
		while (ifs.good()){
			std::cout << c;
			c = ifs.get();
		}
		ifs.close();
		std::cout << '\n';
	}

	{
		os::task_system_t task_system;
		std::cout << task_system << std::endl;

		std::ifstream ifs("system/0", std::ifstream::in);
		os::parse_task_system_stream(ifs, task_system);
		ifs.close();

		std::cout << task_system << std::endl;
	}
	return 0;
}<|endoftext|>


<commit_before>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <list>
#include <set>
#include <cmath>
#include <cassert>
#include <iostream>
#include <iterator>
#include <type_traits>
#include <utility>

#include <vigra/multi_array.hxx>
#include <vigra/linear_algebra.hxx>

template <unsigned int N,
          class T1, class S1,
          class T2, class S2,
          typename std::enable_if<(N == 1)>::type* = nullptr>
inline void lineRankOrderFilter(const vigra::MultiArrayView<N, T1, S1> & src,
                                vigra::MultiArrayView<N, T2, S2> dest,
                                unsigned long half_length, double rank)
{
    // Will ignore boundaries initially.
    // Then will try adding reflection.

    // Rank must be in the range 0 to 1
    assert((0 <= rank) && (rank <= 1));

    const int rank_pos = round(rank * (2*half_length));

    // The position of the
    typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 window_begin(0);
    std::multiset<T1> sorted_window;
    std::list< typename std::multiset<T1>::iterator > window_iters;

    // Get the initial sorted window.
    // Include the reflection.
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(half_length); j > 0; j--)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(0); j <= half_length; j++)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }

    typename std::multiset<T1>::iterator rank_point = sorted_window.begin();

    for (int i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    while ( window_begin < src.size() )
    {
        dest[window_begin] = *rank_point;

        typename std::multiset<T1>::iterator prev_iter(window_iters.front());
        T1 prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        T1 next_value;
        if ( window_begin < (src.size() - half_length) )
        {
            next_value = src[window_begin + half_length];
        }
        else
        {
            next_value = src[2 * src.size() - (window_begin + half_length + 2)];
        }

        if ( ( *rank_point < *prev_iter ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < *prev_iter ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

template <unsigned int N,
          class T1, class S1,
          class T2, class S2,
          typename std::enable_if<(N > 1)>::type* = nullptr>
inline void lineRankOrderFilter(const vigra::MultiArrayView<N, T1, S1> & src,
                                vigra::MultiArrayView<N, T2, S2> dest,
                                unsigned long half_length, double rank, unsigned int axis = N - 1)
{
    typename vigra::MultiArrayView<N, T1, S1>::difference_type transposed_axes;

    for (unsigned int i = 0; i < N; i++)
    {
        transposed_axes[i] = i;
    }

    std::swap(transposed_axes[N - 1], transposed_axes[axis]);

    vigra::MultiArray<N, T1> src_transposed(src.transpose(transposed_axes));

    vigra::MultiArrayView<N, T1, S1> dest_transposed_view(dest.transpose(transposed_axes));

    typename vigra::MultiArrayView<N - 1, T1, S1>::difference_type pos;
    pos = 0;

    bool done = false;

    while (!done)
    {
        lineRankOrderFilter(src_transposed.bindInner(pos), dest_transposed_view.bindInner(pos), half_length, rank);

        bool carry = true;
        for (unsigned int i = 0; ( carry && (i < N) ); i++)
        {
            if ( (++pos[N - (i + 1)]) < src.shape()[N - (i + 1)])
            {
                carry = false;
            }
            else
            {
                pos[N - (i + 1)] = 0;
                carry = true;
            }
        }

        done = !carry;
    }
}

#endif //__RANK_FILTER__
<commit_msg>rank_filter.hxx: Added more spaces to clear up confusion.<commit_after>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <list>
#include <set>
#include <cmath>
#include <cassert>
#include <iostream>
#include <iterator>
#include <type_traits>
#include <utility>

#include <vigra/multi_array.hxx>
#include <vigra/linear_algebra.hxx>

template <unsigned int N,
          class T1, class S1,
          class T2, class S2,
          typename std::enable_if<(N == 1)>::type* = nullptr>
inline void lineRankOrderFilter(const vigra::MultiArrayView<N, T1, S1> & src,
                                vigra::MultiArrayView<N, T2, S2> dest,
                                unsigned long half_length, double rank)
{
    // Will ignore boundaries initially.
    // Then will try adding reflection.

    // Rank must be in the range 0 to 1
    assert((0 <= rank) && (rank <= 1));

    const int rank_pos = round(rank * (2 * half_length));

    // The position of the
    typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 window_begin(0);
    std::multiset<T1> sorted_window;
    std::list< typename std::multiset<T1>::iterator > window_iters;

    // Get the initial sorted window.
    // Include the reflection.
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(half_length); j > 0; j--)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(0); j <= half_length; j++)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }

    typename std::multiset<T1>::iterator rank_point = sorted_window.begin();

    for (int i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    while ( window_begin < src.size() )
    {
        dest[window_begin] = *rank_point;

        typename std::multiset<T1>::iterator prev_iter(window_iters.front());
        T1 prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        T1 next_value;
        if ( window_begin < (src.size() - half_length) )
        {
            next_value = src[window_begin + half_length];
        }
        else
        {
            next_value = src[2 * src.size() - (window_begin + half_length + 2)];
        }

        if ( ( *rank_point < *prev_iter ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < *prev_iter ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

template <unsigned int N,
          class T1, class S1,
          class T2, class S2,
          typename std::enable_if<(N > 1)>::type* = nullptr>
inline void lineRankOrderFilter(const vigra::MultiArrayView<N, T1, S1> & src,
                                vigra::MultiArrayView<N, T2, S2> dest,
                                unsigned long half_length, double rank, unsigned int axis = N - 1)
{
    typename vigra::MultiArrayView<N, T1, S1>::difference_type transposed_axes;

    for (unsigned int i = 0; i < N; i++)
    {
        transposed_axes[i] = i;
    }

    std::swap(transposed_axes[N - 1], transposed_axes[axis]);

    vigra::MultiArray<N, T1> src_transposed(src.transpose(transposed_axes));

    vigra::MultiArrayView<N, T1, S1> dest_transposed_view(dest.transpose(transposed_axes));

    typename vigra::MultiArrayView<N - 1, T1, S1>::difference_type pos;
    pos = 0;

    bool done = false;

    while (!done)
    {
        lineRankOrderFilter(src_transposed.bindInner(pos), dest_transposed_view.bindInner(pos), half_length, rank);

        bool carry = true;
        for (unsigned int i = 0; ( carry && (i < N) ); i++)
        {
            if ( (++pos[N - (i + 1)]) < src.shape()[N - (i + 1)])
            {
                carry = false;
            }
            else
            {
                pos[N - (i + 1)] = 0;
                carry = true;
            }
        }

        done = !carry;
    }
}

#endif //__RANK_FILTER__
<|endoftext|>


<commit_before>//===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the RISCV target.
//
//===----------------------------------------------------------------------===//

#include "RISCV.h"
#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "RISCVTargetMachine.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

#define DEBUG_TYPE "riscv-isel"

// RISCV-specific code to select RISCV machine instructions for
// SelectionDAG operations.
namespace {
class RISCVDAGToDAGISel final : public SelectionDAGISel {
  const RISCVSubtarget *Subtarget;

public:
  explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine)
      : SelectionDAGISel(TargetMachine) {}

  StringRef getPassName() const override {
    return "RISCV DAG->DAG Pattern Instruction Selection";
  }

  bool runOnMachineFunction(MachineFunction &MF) override {
    Subtarget = &MF.getSubtarget<RISCVSubtarget>();
    return SelectionDAGISel::runOnMachineFunction(MF);
  }

  void PostprocessISelDAG() override;

  void Select(SDNode *Node) override;

  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
                                    std::vector<SDValue> &OutOps) override;

  bool SelectAddrFI(SDValue Addr, SDValue &Base);

// Include the pieces autogenerated from the target description.
#include "RISCVGenDAGISel.inc"

private:
  void doPeepholeLoadStoreADDI();
  void doPeepholeBuildPairF64SplitF64();
};
}

void RISCVDAGToDAGISel::PostprocessISelDAG() {
  doPeepholeLoadStoreADDI();
  doPeepholeBuildPairF64SplitF64();
}

void RISCVDAGToDAGISel::Select(SDNode *Node) {
  unsigned Opcode = Node->getOpcode();
  MVT XLenVT = Subtarget->getXLenVT();

  // If we have a custom node, we have already selected
  if (Node->isMachineOpcode()) {
    LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
    Node->setNodeId(-1);
    return;
  }

  // Instruction Selection not handled by the auto-generated tablegen selection
  // should be handled here.
  EVT VT = Node->getValueType(0);
  if (Opcode == ISD::Constant && VT == XLenVT) {
    auto *ConstNode = cast<ConstantSDNode>(Node);
    // Materialize zero constants as copies from X0. This allows the coalescer
    // to propagate these into other instructions.
    if (ConstNode->isNullValue()) {
      SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node),
                                           RISCV::X0, XLenVT);
      ReplaceNode(Node, New.getNode());
      return;
    }
  }
  if (Opcode == ISD::FrameIndex) {
    SDLoc DL(Node);
    SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
    int FI = cast<FrameIndexSDNode>(Node)->getIndex();
    EVT VT = Node->getValueType(0);
    SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
    ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
    return;
  }

  // Select the default instruction.
  SelectCode(Node);
}

bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
    const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
  switch (ConstraintID) {
  case InlineAsm::Constraint_i:
  case InlineAsm::Constraint_m:
    // We just support simple memory operands that have a single address
    // operand and need no special handling.
    OutOps.push_back(Op);
    return false;
  default:
    break;
  }

  return true;
}

bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
  if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
    return true;
  }
  return false;
}

// Merge an ADDI into the offset of a load/store instruction where possible.
// (load (add base, off), 0) -> (load base, off)
// (store val, (add base, off)) -> (store val, base, off)
void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() {
  SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
  ++Position;

  while (Position != CurDAG->allnodes_begin()) {
    SDNode *N = &*--Position;
    // Skip dead nodes and any non-machine opcodes.
    if (N->use_empty() || !N->isMachineOpcode())
      continue;

    int OffsetOpIdx;
    int BaseOpIdx;

    // Only attempt this optimisation for I-type loads and S-type stores.
    switch (N->getMachineOpcode()) {
    default:
      continue;
    case RISCV::LB:
    case RISCV::LH:
    case RISCV::LW:
    case RISCV::LBU:
    case RISCV::LHU:
    case RISCV::LWU:
    case RISCV::LD:
    case RISCV::FLW:
    case RISCV::FLD:
      BaseOpIdx = 0;
      OffsetOpIdx = 1;
      break;
    case RISCV::SB:
    case RISCV::SH:
    case RISCV::SW:
    case RISCV::SD:
    case RISCV::FSW:
    case RISCV::FSD:
      BaseOpIdx = 1;
      OffsetOpIdx = 2;
      break;
    }

    // Currently, the load/store offset must be 0 to be considered for this
    // peephole optimisation.
    if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)) ||
        N->getConstantOperandVal(OffsetOpIdx) != 0)
      continue;

    SDValue Base = N->getOperand(BaseOpIdx);

    // If the base is an ADDI, we can merge it in to the load/store.
    if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
      continue;

    SDValue ImmOperand = Base.getOperand(1);

    if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) {
      ImmOperand = CurDAG->getTargetConstant(
          Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType());
    } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) {
      ImmOperand = CurDAG->getTargetGlobalAddress(
          GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(),
          GA->getOffset(), GA->getTargetFlags());
    } else {
      continue;
    }

    LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase:    ");
    LLVM_DEBUG(Base->dump(CurDAG));
    LLVM_DEBUG(dbgs() << "\nN: ");
    LLVM_DEBUG(N->dump(CurDAG));
    LLVM_DEBUG(dbgs() << "\n");

    // Modify the offset operand of the load/store.
    if (BaseOpIdx == 0) // Load
      CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
                                 N->getOperand(2));
    else // Store
      CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0),
                                 ImmOperand, N->getOperand(3));

    // The add-immediate may now be dead, in which case remove it.
    if (Base.getNode()->use_empty())
      CurDAG->RemoveDeadNode(Base.getNode());
  }
}

// Remove redundant BuildPairF64+SplitF64 pairs. i.e. cases where an f64 is
// built of two i32 values, only to be split apart again. This must be done
// here as a peephole optimisation as the DAG has not been fully legalized at
// the point BuildPairF64/SplitF64 nodes are created in RISCVISelLowering, so
// some nodes would not yet have been replaced with libcalls.
void RISCVDAGToDAGISel::doPeepholeBuildPairF64SplitF64() {
  SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
  ++Position;

  while (Position != CurDAG->allnodes_begin()) {
    SDNode *N = &*--Position;
    // Skip dead nodes and any nodes other than SplitF64Pseudo.
    if (N->use_empty() || !N->isMachineOpcode() ||
        !(N->getMachineOpcode() == RISCV::SplitF64Pseudo))
      continue;

    // If the operand to SplitF64 is a BuildPairF64, the split operation is
    // redundant. Just use the operands to BuildPairF64 as the result.
    SDValue F64Val = N->getOperand(0);
    if (F64Val.isMachineOpcode() &&
        F64Val.getMachineOpcode() == RISCV::BuildPairF64Pseudo) {
      LLVM_DEBUG(
          dbgs() << "Removing redundant SplitF64Pseudo and replacing uses "
                    "with BuildPairF64Pseudo operands:\n");
      LLVM_DEBUG(dbgs() << "N:    ");
      LLVM_DEBUG(N->dump(CurDAG));
      LLVM_DEBUG(dbgs() << "F64Val: ");
      LLVM_DEBUG(F64Val->dump(CurDAG));
      LLVM_DEBUG(dbgs() << "\n");
      SDValue From[] = {SDValue(N, 0), SDValue(N, 1)};
      SDValue To[] = {F64Val.getOperand(0), F64Val.getOperand(1)};
      CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
    }
  }
  CurDAG->RemoveDeadNodes();
}

// This pass converts a legalized DAG into a RISCV-specific DAG, ready
// for instruction scheduling.
FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
  return new RISCVDAGToDAGISel(TM);
}
<commit_msg>[RISCV][NFC] Refactor RISCVDAGToDAGISel::Select<commit_after>//===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the RISCV target.
//
//===----------------------------------------------------------------------===//

#include "RISCV.h"
#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "RISCVTargetMachine.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

#define DEBUG_TYPE "riscv-isel"

// RISCV-specific code to select RISCV machine instructions for
// SelectionDAG operations.
namespace {
class RISCVDAGToDAGISel final : public SelectionDAGISel {
  const RISCVSubtarget *Subtarget;

public:
  explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine)
      : SelectionDAGISel(TargetMachine) {}

  StringRef getPassName() const override {
    return "RISCV DAG->DAG Pattern Instruction Selection";
  }

  bool runOnMachineFunction(MachineFunction &MF) override {
    Subtarget = &MF.getSubtarget<RISCVSubtarget>();
    return SelectionDAGISel::runOnMachineFunction(MF);
  }

  void PostprocessISelDAG() override;

  void Select(SDNode *Node) override;

  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
                                    std::vector<SDValue> &OutOps) override;

  bool SelectAddrFI(SDValue Addr, SDValue &Base);

// Include the pieces autogenerated from the target description.
#include "RISCVGenDAGISel.inc"

private:
  void doPeepholeLoadStoreADDI();
  void doPeepholeBuildPairF64SplitF64();
};
}

void RISCVDAGToDAGISel::PostprocessISelDAG() {
  doPeepholeLoadStoreADDI();
  doPeepholeBuildPairF64SplitF64();
}

void RISCVDAGToDAGISel::Select(SDNode *Node) {
  // If we have a custom node, we have already selected.
  if (Node->isMachineOpcode()) {
    LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
    Node->setNodeId(-1);
    return;
  }

  // Instruction Selection not handled by the auto-generated tablegen selection
  // should be handled here.
  unsigned Opcode = Node->getOpcode();
  MVT XLenVT = Subtarget->getXLenVT();
  SDLoc DL(Node);
  EVT VT = Node->getValueType(0);

  switch (Opcode) {
  case ISD::Constant: {
    auto ConstNode = cast<ConstantSDNode>(Node);
    if (VT == XLenVT && ConstNode->isNullValue()) {
      SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node),
                                           RISCV::X0, XLenVT);
      ReplaceNode(Node, New.getNode());
      return;
    }
    break;
  }
  case ISD::FrameIndex: {
    SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
    int FI = cast<FrameIndexSDNode>(Node)->getIndex();
    SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
    ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
    return;
  }
  }

  // Select the default instruction.
  SelectCode(Node);
}

bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
    const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
  switch (ConstraintID) {
  case InlineAsm::Constraint_i:
  case InlineAsm::Constraint_m:
    // We just support simple memory operands that have a single address
    // operand and need no special handling.
    OutOps.push_back(Op);
    return false;
  default:
    break;
  }

  return true;
}

bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
  if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
    return true;
  }
  return false;
}

// Merge an ADDI into the offset of a load/store instruction where possible.
// (load (add base, off), 0) -> (load base, off)
// (store val, (add base, off)) -> (store val, base, off)
void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() {
  SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
  ++Position;

  while (Position != CurDAG->allnodes_begin()) {
    SDNode *N = &*--Position;
    // Skip dead nodes and any non-machine opcodes.
    if (N->use_empty() || !N->isMachineOpcode())
      continue;

    int OffsetOpIdx;
    int BaseOpIdx;

    // Only attempt this optimisation for I-type loads and S-type stores.
    switch (N->getMachineOpcode()) {
    default:
      continue;
    case RISCV::LB:
    case RISCV::LH:
    case RISCV::LW:
    case RISCV::LBU:
    case RISCV::LHU:
    case RISCV::LWU:
    case RISCV::LD:
    case RISCV::FLW:
    case RISCV::FLD:
      BaseOpIdx = 0;
      OffsetOpIdx = 1;
      break;
    case RISCV::SB:
    case RISCV::SH:
    case RISCV::SW:
    case RISCV::SD:
    case RISCV::FSW:
    case RISCV::FSD:
      BaseOpIdx = 1;
      OffsetOpIdx = 2;
      break;
    }

    // Currently, the load/store offset must be 0 to be considered for this
    // peephole optimisation.
    if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)) ||
        N->getConstantOperandVal(OffsetOpIdx) != 0)
      continue;

    SDValue Base = N->getOperand(BaseOpIdx);

    // If the base is an ADDI, we can merge it in to the load/store.
    if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
      continue;

    SDValue ImmOperand = Base.getOperand(1);

    if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) {
      ImmOperand = CurDAG->getTargetConstant(
          Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType());
    } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) {
      ImmOperand = CurDAG->getTargetGlobalAddress(
          GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(),
          GA->getOffset(), GA->getTargetFlags());
    } else {
      continue;
    }

    LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase:    ");
    LLVM_DEBUG(Base->dump(CurDAG));
    LLVM_DEBUG(dbgs() << "\nN: ");
    LLVM_DEBUG(N->dump(CurDAG));
    LLVM_DEBUG(dbgs() << "\n");

    // Modify the offset operand of the load/store.
    if (BaseOpIdx == 0) // Load
      CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
                                 N->getOperand(2));
    else // Store
      CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0),
                                 ImmOperand, N->getOperand(3));

    // The add-immediate may now be dead, in which case remove it.
    if (Base.getNode()->use_empty())
      CurDAG->RemoveDeadNode(Base.getNode());
  }
}

// Remove redundant BuildPairF64+SplitF64 pairs. i.e. cases where an f64 is
// built of two i32 values, only to be split apart again. This must be done
// here as a peephole optimisation as the DAG has not been fully legalized at
// the point BuildPairF64/SplitF64 nodes are created in RISCVISelLowering, so
// some nodes would not yet have been replaced with libcalls.
void RISCVDAGToDAGISel::doPeepholeBuildPairF64SplitF64() {
  SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
  ++Position;

  while (Position != CurDAG->allnodes_begin()) {
    SDNode *N = &*--Position;
    // Skip dead nodes and any nodes other than SplitF64Pseudo.
    if (N->use_empty() || !N->isMachineOpcode() ||
        !(N->getMachineOpcode() == RISCV::SplitF64Pseudo))
      continue;

    // If the operand to SplitF64 is a BuildPairF64, the split operation is
    // redundant. Just use the operands to BuildPairF64 as the result.
    SDValue F64Val = N->getOperand(0);
    if (F64Val.isMachineOpcode() &&
        F64Val.getMachineOpcode() == RISCV::BuildPairF64Pseudo) {
      LLVM_DEBUG(
          dbgs() << "Removing redundant SplitF64Pseudo and replacing uses "
                    "with BuildPairF64Pseudo operands:\n");
      LLVM_DEBUG(dbgs() << "N:    ");
      LLVM_DEBUG(N->dump(CurDAG));
      LLVM_DEBUG(dbgs() << "F64Val: ");
      LLVM_DEBUG(F64Val->dump(CurDAG));
      LLVM_DEBUG(dbgs() << "\n");
      SDValue From[] = {SDValue(N, 0), SDValue(N, 1)};
      SDValue To[] = {F64Val.getOperand(0), F64Val.getOperand(1)};
      CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
    }
  }
  CurDAG->RemoveDeadNodes();
}

// This pass converts a legalized DAG into a RISCV-specific DAG, ready
// for instruction scheduling.
FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
  return new RISCVDAGToDAGISel(TM);
}
<|endoftext|>


<commit_before>//
//  inpalprime.hpp
//  InPal
//
//  Created by Bryan Triana on 6/21/16.
//  Copyright © 2016 Inverse Palindrome. All rights reserved.
//

#ifndef inpalprime_hpp
#define inpalprime_hpp

#include <vector>
#include <string>

class inpalprime
{

public:
    unsigned long long pn_find(unsigned long long n);
    unsigned long long pn_count(unsigned long long n);
    long double pn_den(long double h);
    bool pn_test(unsigned long long a);
    bool pn_twin(unsigned long long a);
    bool pn_cousin(unsigned long long a);
    bool pn_sexy(unsigned long long a);
    unsigned long long pn_pal(unsigned long long n);
    unsigned long long n_fac(unsigned long long f);
    unsigned long long n_cfac(unsigned long long f);

private:
    std::vector<bool> atkinsieve(unsigned long long m);
    std::vector<unsigned long long> factorizer(unsigned long long f);
    bool pal_test(unsigned long long n);
    unsigned long long maxprime=0;
    unsigned long long primecount=0;
    long double primeden;
    unsigned long long pal;
    std::string ull;
    unsigned long long maxfac;
    unsigned long long cfac;

};

#endif /* inpalprime_hpp */
<commit_msg>Update inpalprime.hpp<commit_after>//
//  inpalprime.hpp
//  InPal
//
//  Created by Bryan Triana on 6/21/16.
//  Copyright © 2016 Inverse Palindrome. All rights reserved.
//

#ifndef inpalprime_hpp
#define inpalprime_hpp

#include <vector>
#include <string>

class inpalprime
{

public:
    long long pn_find(long long n);
    long long pn_count(long long n);
    long double pn_den(long double h);
    bool pn_test(long long a);
    bool pn_twin(long long a);
    bool pn_cousin(long long a);
    bool pn_sexy(long long a);
    long long pn_pal(long long n);
    long long n_fac(long long f);
    long long n_cfac(long long f);

private:
    std::vector<bool> atkinsieve(long long m);
    std::vector<long long> factorizer(long long f);
    bool pal_test(long long n);
    long long maxprime=0;
    long long primecount;
    long double primeden;
    long long pal;
    std::string ull;
    long long maxfac;
    long long cfac;

};

#endif /* inpalprime_hpp */
<|endoftext|>


<commit_before>/*****************************************************************************\
 *                        ANALYSIS PERFORMANCE TOOLS                         *
 *                                  wxparaver                                *
 *              Paraver Trace Visualization and Analysis Tool                *
 *****************************************************************************
 *     ___     This library is free software; you can redistribute it and/or *
 *    /  __         modify it under the terms of the GNU LGPL as published   *
 *   /  /  _____    by the Free Software Foundation; either version 2.1      *
 *  /  /  /     \   of the License, or (at your option) any later version.   *
 * (  (  ( B S C )                                                           *
 *  \  \  \_____/   This library is distributed in hope that it will be      *
 *   \  \__         useful but WITHOUT ANY WARRANTY; without even the        *
 *    \___          implied warranty of MERCHANTABILITY or FITNESS FOR A     *
 *                  PARTICULAR PURPOSE. See the GNU LGPL for more details.   *
 *                                                                           *
 * You should have received a copy of the GNU Lesser General Public License  *
 * along with this library; if not, write to the Free Software Foundation,   *
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA          *
 * The GNU LEsser General Public License is contained in the file COPYING.   *
 *                                 ---------                                 *
 *   Barcelona Supercomputing Center - Centro Nacional de Supercomputacion   *
\*****************************************************************************/

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *\
 | @file: $HeadURL$
 | @last_commit: $Date$
 | @version:     $Revision$
\* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <string>
#include <wx/filename.h>
#include "sequencedriver.h"
#include "kernelconnection.h"
#include "gtimeline.h"
#include "traceeditsequence.h"
#include "traceeditstates.h"
#include "traceoptions.h"
#include "runscript.h"
#include "wxparaverapp.h"

/****************************************************************************
 ********             RunAppClusteringAction                         ********
 ****************************************************************************/
vector<TraceEditSequence::TSequenceStates> RunAppClusteringAction::getStateDependencies() const
{
  vector<TraceEditSequence::TSequenceStates> tmpStates;
  return tmpStates;
}

void RunAppClusteringAction::execute( std::string whichTrace )
{
  TraceEditSequence *tmpSequence = (TraceEditSequence *)mySequence;
  std::string tmpFileName = ( (CSVFileNameState *)tmpSequence->getState( TraceEditSequence::csvFileNameState ) )->getData();
  RunScript runAppDialog( wxparaverApp::mainWindow, wxString::FromAscii( whichTrace.c_str() ) );
  runAppDialog.setClustering( wxString::FromAscii( tmpFileName.c_str() ) );

  if( runAppDialog.ShowModal() == wxID_OK )
  {}
}

/****************************************************************************
 ********                 SequenceDriver                             ********
 ****************************************************************************/
void SequenceDriver::sequenceClustering( gTimeline *whichTimeline )
{
  KernelConnection *myKernel =  whichTimeline->GetMyWindow()->getKernel();
  TraceEditSequence *mySequence = TraceEditSequence::create( myKernel );

  mySequence->pushbackAction( TraceEditSequence::traceCutterAction );
  mySequence->pushbackAction( TraceEditSequence::csvOutputAction );
  mySequence->pushbackAction( new RunAppClusteringAction( mySequence ) );

  TraceOptions *tmpOptions = TraceOptions::create( myKernel );
  tmpOptions->set_by_time( true );
  tmpOptions->set_min_cutting_time( whichTimeline->GetMyWindow()->getWindowBeginTime() );
  tmpOptions->set_max_cutting_time( whichTimeline->GetMyWindow()->getWindowEndTime() );
  tmpOptions->set_original_time( true );
  tmpOptions->set_break_states( false );

  TraceOptionsState *tmpOptionsState = new TraceOptionsState( mySequence );
  tmpOptionsState->setData( tmpOptions );
  mySequence->addState( TraceEditSequence::traceOptionsState, tmpOptionsState );

  TextOutput output;
  output.setObjectHierarchy( true );
  output.setWindowTimeUnits( false );
  CSVOutputState *tmpOutputState = new CSVOutputState( mySequence );
  tmpOutputState->setData( output );
  mySequence->addState( TraceEditSequence::csvOutputState, tmpOutputState );

  CSVWindowState *tmpWindowState = new CSVWindowState( mySequence );
  tmpWindowState->setData( whichTimeline->GetMyWindow() );
  mySequence->addState( TraceEditSequence::csvWindowState, tmpWindowState );

  CSVFileNameState *tmpCSVFilenameState = new CSVFileNameState( mySequence );
  std::string tmpFileName;
  wxFileName tmpTraceName( wxString::FromAscii( whichTimeline->GetMyWindow()->getTrace()->getFileName().c_str() ) );
  tmpTraceName.ClearExt();
  tmpTraceName.AppendDir( wxString::FromAscii( TraceEditSequence::dirNameClustering.c_str() ) );

  if( !tmpTraceName.DirExists() )
    tmpTraceName.Mkdir();
  std::string auxName = whichTimeline->GetMyWindow()->getName() + "_";
  tmpFileName = std::string( tmpTraceName.GetPath( wxPATH_GET_SEPARATOR ).mb_str() ) + auxName.c_str() + std::string( tmpTraceName.GetFullName().mb_str() ) + std::string( ".csv" );

  tmpCSVFilenameState->setData( tmpFileName );
  mySequence->addState( TraceEditSequence::csvFileNameState, tmpCSVFilenameState );

  vector<std::string> traces;
  traces.push_back( whichTimeline->GetMyWindow()->getTrace()->getFileName() );
  mySequence->execute( traces );

  delete mySequence;
}
<commit_msg>*** empty log message ***<commit_after>/*****************************************************************************\
 *                        ANALYSIS PERFORMANCE TOOLS                         *
 *                                  wxparaver                                *
 *              Paraver Trace Visualization and Analysis Tool                *
 *****************************************************************************
 *     ___     This library is free software; you can redistribute it and/or *
 *    /  __         modify it under the terms of the GNU LGPL as published   *
 *   /  /  _____    by the Free Software Foundation; either version 2.1      *
 *  /  /  /     \   of the License, or (at your option) any later version.   *
 * (  (  ( B S C )                                                           *
 *  \  \  \_____/   This library is distributed in hope that it will be      *
 *   \  \__         useful but WITHOUT ANY WARRANTY; without even the        *
 *    \___          implied warranty of MERCHANTABILITY or FITNESS FOR A     *
 *                  PARTICULAR PURPOSE. See the GNU LGPL for more details.   *
 *                                                                           *
 * You should have received a copy of the GNU Lesser General Public License  *
 * along with this library; if not, write to the Free Software Foundation,   *
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA          *
 * The GNU LEsser General Public License is contained in the file COPYING.   *
 *                                 ---------                                 *
 *   Barcelona Supercomputing Center - Centro Nacional de Supercomputacion   *
\*****************************************************************************/

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *\
 | @file: $HeadURL$
 | @last_commit: $Date$
 | @version:     $Revision$
\* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <string>
#include <wx/filename.h>
#include "sequencedriver.h"
#include "kernelconnection.h"
#include "gtimeline.h"
#include "traceeditsequence.h"
#include "traceeditstates.h"
#include "traceoptions.h"
#include "runscript.h"
#include "wxparaverapp.h"

/****************************************************************************
 ********             RunAppClusteringAction                         ********
 ****************************************************************************/
vector<TraceEditSequence::TSequenceStates> RunAppClusteringAction::getStateDependencies() const
{
  vector<TraceEditSequence::TSequenceStates> tmpStates;
  return tmpStates;
}

void RunAppClusteringAction::execute( std::string whichTrace )
{
  TraceEditSequence *tmpSequence = (TraceEditSequence *)mySequence;
  std::string tmpFileName = ( (CSVFileNameState *)tmpSequence->getState( TraceEditSequence::csvFileNameState ) )->getData();
  RunScript runAppDialog( wxparaverApp::mainWindow, wxString::FromAscii( whichTrace.c_str() ) );
  runAppDialog.setClustering( wxString::FromAscii( tmpFileName.c_str() ) );

  if( runAppDialog.ShowModal() == wxID_OK )
  {}
}

/****************************************************************************
 ********                 SequenceDriver                             ********
 ****************************************************************************/
void SequenceDriver::sequenceClustering( gTimeline *whichTimeline )
{
  KernelConnection *myKernel =  whichTimeline->GetMyWindow()->getKernel();
  TraceEditSequence *mySequence = TraceEditSequence::create( myKernel );

  mySequence->pushbackAction( TraceEditSequence::traceCutterAction );
  mySequence->pushbackAction( TraceEditSequence::csvOutputAction );
  mySequence->pushbackAction( new RunAppClusteringAction( mySequence ) );

  TraceOptions *tmpOptions = TraceOptions::create( myKernel );
  tmpOptions->set_by_time( true );
  tmpOptions->set_min_cutting_time( whichTimeline->GetMyWindow()->getWindowBeginTime() );
  tmpOptions->set_max_cutting_time( whichTimeline->GetMyWindow()->getWindowEndTime() );
  tmpOptions->set_original_time( false );
  tmpOptions->set_break_states( false );

  TraceOptionsState *tmpOptionsState = new TraceOptionsState( mySequence );
  tmpOptionsState->setData( tmpOptions );
  mySequence->addState( TraceEditSequence::traceOptionsState, tmpOptionsState );

  TextOutput output;
  output.setObjectHierarchy( true );
  output.setWindowTimeUnits( false );
  CSVOutputState *tmpOutputState = new CSVOutputState( mySequence );
  tmpOutputState->setData( output );
  mySequence->addState( TraceEditSequence::csvOutputState, tmpOutputState );

  CSVWindowState *tmpWindowState = new CSVWindowState( mySequence );
  tmpWindowState->setData( whichTimeline->GetMyWindow() );
  mySequence->addState( TraceEditSequence::csvWindowState, tmpWindowState );

  CSVFileNameState *tmpCSVFilenameState = new CSVFileNameState( mySequence );
  std::string tmpFileName;
  wxFileName tmpTraceName( wxString::FromAscii( whichTimeline->GetMyWindow()->getTrace()->getFileName().c_str() ) );
  tmpTraceName.ClearExt();
  tmpTraceName.AppendDir( wxString::FromAscii( TraceEditSequence::dirNameClustering.c_str() ) );

  if( !tmpTraceName.DirExists() )
    tmpTraceName.Mkdir();
  std::string auxName = whichTimeline->GetMyWindow()->getName() + "_";
  tmpFileName = std::string( tmpTraceName.GetPath( wxPATH_GET_SEPARATOR ).mb_str() ) + auxName.c_str() + std::string( tmpTraceName.GetFullName().mb_str() ) + std::string( ".csv" );

  tmpCSVFilenameState->setData( tmpFileName );
  mySequence->addState( TraceEditSequence::csvFileNameState, tmpCSVFilenameState );

  vector<std::string> traces;
  traces.push_back( whichTimeline->GetMyWindow()->getTrace()->getFileName() );
  mySequence->execute( traces );

  delete mySequence;
}
<|endoftext|>


<commit_before>/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013, 2014 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

 Infomap software package is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

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

 You should have received a copy of the GNU Affero General Public License
 along with Infomap software package.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************/

#include "version.h"

#ifdef NS_INFOMAP
namespace infomap
{
#endif

const char* INFOMAP_VERSION = "0.18.7";

#ifdef NS_INFOMAP
}
#endif
<commit_msg>Patch version<commit_after>/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013, 2014 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

 Infomap software package is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

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

 You should have received a copy of the GNU Affero General Public License
 along with Infomap software package.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************/

#include "version.h"

#ifdef NS_INFOMAP
namespace infomap
{
#endif

const char* INFOMAP_VERSION = "0.18.8";

#ifdef NS_INFOMAP
}
#endif
<|endoftext|>


<commit_before>#include "layers/lsh.h"
#include "3rd_party/faiss/IndexLSH.h"
#include "graph/expression_operators.h"
#include "tensors/cpu/prod_blas.h"

namespace marian {

Expr LSH::apply(Expr input, Expr W, Expr b) {
  auto idx = search(input, W);
  return affine(idx, input, W, b);
}

Expr LSH::search(Expr query, Expr values) {
  ABORT_IF(query->graph()->getDeviceId().type == DeviceType::gpu,
           "LSH index (--output-approx-knn) currently not implemented for GPU");

  auto kShape = query->shape();
  kShape.set(-1, k_);

  auto forward = [this](Expr out, const std::vector<Expr>& inputs) {
    auto query  = inputs[0];
    auto values = inputs[1];

    int dim = values->shape()[-1];

    if(!index_ || indexHash_ != values->hash()) {
      LOG(info, "Building LSH index for vector dim {} and with hash size {} bits", dim, nbits_);
      index_.reset(new faiss::IndexLSH(dim, nbits_,
                                       /*rotate=*/dim != nbits_,
                                       /*train_thesholds*/false));
      int vRows = values->shape().elements() / dim;
      index_->train(vRows, values->val()->data<float>());
      index_->add(  vRows, values->val()->data<float>());
      indexHash_ = values->hash();
    }

    int qRows = query->shape().elements() / dim;
    std::vector<float> distances(qRows * k_);
    std::vector<faiss::Index::idx_t> ids(qRows * k_);

    index_->search(qRows, query->val()->data<float>(), k_,
                   distances.data(), ids.data());

    std::vector<IndexType> vOut;
    vOut.reserve(ids.size());
    for(auto id : ids)
      vOut.push_back((IndexType)id);

    out->val()->set(vOut);
  };

  return lambda({query, values}, kShape, Type::uint32, forward);
}

Expr LSH::affine(Expr idx, Expr input, Expr W, Expr b) {
  auto outShape = input->shape();
  int dimVoc    = W->shape()[-2];
  outShape.set(-1, dimVoc);

  auto forward = [this](Expr out, const std::vector<Expr>& inputs) {
    auto lowest = NumericLimits<float>(out->value_type()).lowest;
    out->val()->set(lowest);

    int dimIn   = inputs[1]->shape()[-1];
    int dimOut  = out->shape()[-1];
    int dimRows = out->shape().elements() / dimOut;

    auto outPtr   = out->val()->data<float>();
    auto idxPtr   = inputs[0]->val()->data<uint32_t>();
    auto queryPtr = inputs[1]->val()->data<float>();
    auto WPtr     = inputs[2]->val()->data<float>();
    auto bPtr     = inputs.size() > 3 ? inputs[3]->val()->data<float>() : nullptr; // nullptr if no bias given

    for(int row = 0; row < dimRows; ++row) {
      auto currIdxPtr    = idxPtr   + row * k_;     // move to next batch of k entries
      auto currQueryPtr  = queryPtr + row * dimIn;  // move to next input query vector
      auto currOutPtr    = outPtr   + row * dimOut; // move to next output position vector (of vocabulary size)
      for(int k = 0; k < k_; k++) {
        int relPos = currIdxPtr[k];                   // k-th best vocabulay item
        auto currWPtr      = WPtr + relPos * dimIn;   // offset for k-th best embedding
        currOutPtr[relPos] = bPtr ? bPtr[relPos] : 0; // write bias value to position, init to 0 if no bias given

        // proceed one vector product at a time writing to the correct position
        sgemm(false, true, 1, 1, dimIn, 1.0f, currQueryPtr, dimIn, currWPtr, dimIn, 1.0f, &currOutPtr[relPos], 1);
      }
    }
  };

  std::vector<Expr> nodes = {idx, input, W};
  if(b) // bias is optional
    nodes.push_back(b);

  return lambda(nodes,
                outShape,
                input->value_type(),
                forward);
}

// @TODO: alternative version which does the same as above with Marian operators, currently missing "scatter".
// this uses more memory and likely to be slower. Would make sense to have a scatter node that actually creates
// the node instead of relying on an existing node, e.g. scatter(shape, defaultValue, axis, indices, values);
#if 0
Expr LSH::affine(Expr idx, Expr input, Expr W, Expr b) {
  int dim  = input->shape()[-1];
  int bch  = idx->shape().elements() / k;

  auto W = reshape(rows(Wt_, flatten(idx)), {bch, k, dim}); // [rows, k, dim]
  auto b = reshape(cols(b_,  flatten(idx)), {bch, 1,   k}); // [rows, 1,   k]

  auto aff = reshape(bdot(reshape(input, {bch, 1, dim}), W, false, true) + b, idx->shape()); // [beam, time, batch, k]

  int dimVoc  = Wt_->shape()[-2];
  auto oShape = input->shape();
  oShape.set(-1, dimVoc);
  auto lowest = graph_->constant(oShape,
                                 inits::fromValue(NumericLimits<float>(input->value_type()).lowest),
                                 input->value_type());
  return scatter(lowest, -1, idx, aff);
}
#endif

}  // namespace marian<commit_msg>fix compilation with -DCOMPILE_CPU=off<commit_after>#include "layers/lsh.h"
#include "graph/expression_operators.h"
#include "tensors/cpu/prod_blas.h"

#if BLAS_FOUND
#include "3rd_party/faiss/IndexLSH.h"
#endif

namespace marian {

Expr LSH::apply(Expr input, Expr W, Expr b) {
  auto idx = search(input, W);
  return affine(idx, input, W, b);
}

Expr LSH::search(Expr query, Expr values) {
#if BLAS_FOUND
  ABORT_IF(query->graph()->getDeviceId().type == DeviceType::gpu,
           "LSH index (--output-approx-knn) currently not implemented for GPU");

  auto kShape = query->shape();
  kShape.set(-1, k_);

  auto forward = [this](Expr out, const std::vector<Expr>& inputs) {
    auto query  = inputs[0];
    auto values = inputs[1];

    int dim = values->shape()[-1];

    if(!index_ || indexHash_ != values->hash()) {
      LOG(info, "Building LSH index for vector dim {} and with hash size {} bits", dim, nbits_);
      index_.reset(new faiss::IndexLSH(dim, nbits_,
                                       /*rotate=*/dim != nbits_,
                                       /*train_thesholds*/false));
      int vRows = values->shape().elements() / dim;
      index_->train(vRows, values->val()->data<float>());
      index_->add(  vRows, values->val()->data<float>());
      indexHash_ = values->hash();
    }

    int qRows = query->shape().elements() / dim;
    std::vector<float> distances(qRows * k_);
    std::vector<faiss::Index::idx_t> ids(qRows * k_);

    index_->search(qRows, query->val()->data<float>(), k_,
                   distances.data(), ids.data());

    std::vector<IndexType> vOut;
    vOut.reserve(ids.size());
    for(auto id : ids)
      vOut.push_back((IndexType)id);

    out->val()->set(vOut);
  };

  return lambda({query, values}, kShape, Type::uint32, forward);
#else
  query; values;
  ABORT("LSH output layer requires a CPU BLAS library");
#endif
}

Expr LSH::affine(Expr idx, Expr input, Expr W, Expr b) {
  auto outShape = input->shape();
  int dimVoc    = W->shape()[-2];
  outShape.set(-1, dimVoc);

  auto forward = [this](Expr out, const std::vector<Expr>& inputs) {
    auto lowest = NumericLimits<float>(out->value_type()).lowest;
    out->val()->set(lowest);

    int dimIn   = inputs[1]->shape()[-1];
    int dimOut  = out->shape()[-1];
    int dimRows = out->shape().elements() / dimOut;

    auto outPtr   = out->val()->data<float>();
    auto idxPtr   = inputs[0]->val()->data<uint32_t>();
    auto queryPtr = inputs[1]->val()->data<float>();
    auto WPtr     = inputs[2]->val()->data<float>();
    auto bPtr     = inputs.size() > 3 ? inputs[3]->val()->data<float>() : nullptr; // nullptr if no bias given

    for(int row = 0; row < dimRows; ++row) {
      auto currIdxPtr    = idxPtr   + row * k_;     // move to next batch of k entries
      auto currQueryPtr  = queryPtr + row * dimIn;  // move to next input query vector
      auto currOutPtr    = outPtr   + row * dimOut; // move to next output position vector (of vocabulary size)
      for(int k = 0; k < k_; k++) {
        int relPos = currIdxPtr[k];                   // k-th best vocabulay item
        auto currWPtr      = WPtr + relPos * dimIn;   // offset for k-th best embedding
        currOutPtr[relPos] = bPtr ? bPtr[relPos] : 0; // write bias value to position, init to 0 if no bias given

        // proceed one vector product at a time writing to the correct position
        sgemm(false, true, 1, 1, dimIn, 1.0f, currQueryPtr, dimIn, currWPtr, dimIn, 1.0f, &currOutPtr[relPos], 1);
      }
    }
  };

  std::vector<Expr> nodes = {idx, input, W};
  if(b) // bias is optional
    nodes.push_back(b);

  return lambda(nodes,
                outShape,
                input->value_type(),
                forward);
}

// @TODO: alternative version which does the same as above with Marian operators, currently missing "scatter".
// this uses more memory and likely to be slower. Would make sense to have a scatter node that actually creates
// the node instead of relying on an existing node, e.g. scatter(shape, defaultValue, axis, indices, values);
#if 0
Expr LSH::affine(Expr idx, Expr input, Expr W, Expr b) {
  int dim  = input->shape()[-1];
  int bch  = idx->shape().elements() / k;

  auto W = reshape(rows(Wt_, flatten(idx)), {bch, k, dim}); // [rows, k, dim]
  auto b = reshape(cols(b_,  flatten(idx)), {bch, 1,   k}); // [rows, 1,   k]

  auto aff = reshape(bdot(reshape(input, {bch, 1, dim}), W, false, true) + b, idx->shape()); // [beam, time, batch, k]

  int dimVoc  = Wt_->shape()[-2];
  auto oShape = input->shape();
  oShape.set(-1, dimVoc);
  auto lowest = graph_->constant(oShape,
                                 inits::fromValue(NumericLimits<float>(input->value_type()).lowest),
                                 input->value_type());
  return scatter(lowest, -1, idx, aff);
}
#endif

}  // namespace marian<|endoftext|>


<commit_before>#include "model.h"
#include <memory>
#include <algorithm>
#include <vector>

using std::min;
using std::max;
using std::make_shared;

BoundingBox getBoundingBox(const Track &track) {
    BoundingBox res;
    res.leftDown = res.rightUp = track[0];
    for (Point p : track.points) {
        res.leftDown.x = min(res.leftDown.x, p.x);
        res.leftDown.y = min(res.leftDown.y, p.y);
        res.rightUp.x = max(res.rightUp.x, p.x);
        res.rightUp.y = max(res.rightUp.y, p.y);
    }
    return res;
}

double getCircumference(const Track &track) {
    double res = 0;
    for (size_t i = 0; i + 1 < track.size(); i++) {
        res += (track[i + 1] - track[i]).length();
    }
    return res;
}
double getClosedCircumference(const Track &track) {
    double res = getCircumference(track);
    res += (track[0] - track[track.size() - 1]).length();
    return res;
}

bool isClosed(const Track &track) {
    return (track[0] - track[track.size() - 1]).length() <= 10;
}

bool fitsToTrack(const Track &track, const PFigure &figure) {
    // Point should fall nearer than 10 pixels
    BoundingBox box = getBoundingBox(track);
    double maxDistance = 10;
    maxDistance = std::min(maxDistance, std::min(box.width(), box.height()) * 0.2);

    int goodCount = 0;
    for (Point p : track.points) {
        goodCount += figure->getApproximateDistanceToBorder(p) <= maxDistance;
    }

    // At least 95% of points fall nearer than 'maxDistance'
    return goodCount * 100 / track.size() >= 95;
}

using namespace figures;

bool recognizeMove(const Track &track, Model &model) {
    Point start = track[0];
    Point end = track[track.size() - 1];
    for (PFigure figure : model) {
        if (figure->getApproximateDistanceToBorder(start) < 10) { // grabbed
            figure->translate(end - start);
            return true;
        }
    }
    return false;
}

void recognize(const Track &track, Model &model) {
    if (track.empty()) { return; }

    // Moving
    if (recognizeMove(track, model)) {
        return;
    }

    // Drawing new figures

    // Ignore very small tracks
    if (getClosedCircumference(track) < 10) { return; }

    std::vector<PFigure> candidates;
    if (!isClosed(track))  {
        candidates.push_back(make_shared<Segment>(track[0], track[track.size() - 1]));
    } else {
        candidates.push_back(make_shared<Ellipse>(getBoundingBox(track)));
        candidates.push_back(make_shared<Rectangle>(getBoundingBox(track)));
    }
    for (PFigure figure : candidates)
        if (fitsToTrack(track, figure)) {
            model.addFigure(figure);
            break;
        }
}
<commit_msg>recognition: recognizeMove --> recognizeGrabs; connection gesture was added (#12)<commit_after>#include "model.h"
#include <memory>
#include <algorithm>
#include <vector>

using std::min;
using std::max;
using std::make_shared;
using std::dynamic_pointer_cast;

BoundingBox getBoundingBox(const Track &track) {
    BoundingBox res;
    res.leftDown = res.rightUp = track[0];
    for (Point p : track.points) {
        res.leftDown.x = min(res.leftDown.x, p.x);
        res.leftDown.y = min(res.leftDown.y, p.y);
        res.rightUp.x = max(res.rightUp.x, p.x);
        res.rightUp.y = max(res.rightUp.y, p.y);
    }
    return res;
}

double getCircumference(const Track &track) {
    double res = 0;
    for (size_t i = 0; i + 1 < track.size(); i++) {
        res += (track[i + 1] - track[i]).length();
    }
    return res;
}
double getClosedCircumference(const Track &track) {
    double res = getCircumference(track);
    res += (track[0] - track[track.size() - 1]).length();
    return res;
}

bool isClosed(const Track &track) {
    return (track[0] - track[track.size() - 1]).length() <= 10;
}

bool fitsToTrack(const Track &track, const PFigure &figure) {
    // Point should fall nearer than 10 pixels
    BoundingBox box = getBoundingBox(track);
    double maxDistance = 10;
    maxDistance = std::min(maxDistance, std::min(box.width(), box.height()) * 0.2);

    int goodCount = 0;
    for (Point p : track.points) {
        goodCount += figure->getApproximateDistanceToBorder(p) <= maxDistance;
    }

    // At least 95% of points fall nearer than 'maxDistance'
    return goodCount * 100 / track.size() >= 95;
}

using namespace figures;

bool recognizeGrabs(const Track &track, Model &model) {
    Point start = track[0];
    Point end = track[track.size() - 1];

    for (PFigure figure : model) {
        if (figure->getApproximateDistanceToBorder(start) < 10) { // grabbed
            // try connection first
            auto figA = dynamic_pointer_cast<BoundedFigure>(figure);
            if (figA) {
                for (PFigure figure2 : model) {
                    auto figB = dynamic_pointer_cast<BoundedFigure>(figure2);
                    if (figB && figB->getApproximateDistanceToBorder(end) < 10) {
                        model.addFigure(make_shared<SegmentConnection>(figA, figB));
                        return true;
                    }
                }
            }

            // now we try translation
            figure->translate(end - start);
            model.recalculate();
            return true;
        }
    }
    return false;
}

void recognize(const Track &track, Model &model) {
    if (track.empty()) { return; }

    // Moving and connecting
    if (recognizeGrabs(track, model)) {
        return;
    }

    // Drawing new figures

    // Ignore very small tracks
    if (getClosedCircumference(track) < 10) { return; }

    std::vector<PFigure> candidates;
    if (!isClosed(track))  {
        candidates.push_back(make_shared<Segment>(track[0], track[track.size() - 1]));
    } else {
        candidates.push_back(make_shared<Ellipse>(getBoundingBox(track)));
        candidates.push_back(make_shared<Rectangle>(getBoundingBox(track)));
    }
    for (PFigure figure : candidates)
        if (fitsToTrack(track, figure)) {
            model.addFigure(figure);
            break;
        }
}
<|endoftext|>