<commit_before>#ifndef MJOLNIR_OMP_FORCE_FIELD_HPP
#define MJOLNIR_OMP_FORCE_FIELD_HPP
#include <mjolnir/core/ForceField.hpp>
#include <mjolnir/omp/System.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT>
class ForceField<OpenMPSimulatorTraits<realT, boundaryT>>
{
  public:
    using traits_type              = OpenMPSimulatorTraits<realT, boundaryT>;
    using real_type                = typename traits_type::real_type;
    using coordinate_type          = typename traits_type::coordinate_type;
    using system_type              = System<traits_type>;
    using local_forcefield_type    = LocalForceField<traits_type>;
    using global_forcefield_type   = GlobalForceField<traits_type>;
    using external_forcefield_type = ExternalForceField<traits_type>;

  public:

    ForceField(local_forcefield_type&& local, global_forcefield_type&& global)
        : local_(std::move(local)), global_(std::move(global))
    {}
    ForceField(local_forcefield_type&&    local,
               global_forcefield_type&&   global,
               external_forcefield_type&& external)
        : local_(std::move(local)), global_(std::move(global)),
          external_(std::move(external))
    {}
    ForceField()  = default;
    ~ForceField() = default;
    ForceField(const ForceField&) = delete;
    ForceField(ForceField&&)      = default;
    ForceField& operator=(const ForceField&) = delete;
    ForceField& operator=(ForceField&&)      = default;

    // this modify system::topology by using local interaction info.
    void initialize(system_type& sys)
    {
        // first, fetch current topology
        local_.write_topology(sys.topology());
        sys.topology().construct_molecules();

        // based on the topology, make exclusion list
        local_   .initialize(sys);
        global_  .initialize(sys);
        external_.initialize(sys);
    }

    // update parameters like temperature, ionic concentration, etc...
    void update(const system_type& sys)
    {
        local_   .update(sys);
        global_  .update(sys);
        external_.update(sys);
    }

    // update margin of neighbor list
    void update_margin(const real_type dmargin, const system_type& sys)
    {
        local_   .update_margin(dmargin, sys);
        global_  .update_margin(dmargin, sys);
        external_.update_margin(dmargin, sys);
    }

    void calc_force(system_type& sys) const noexcept
    {
#pragma omp parallel
        {
            // calc_force uses `nowait` to speedup. To do that, it needs to be
            // inside a parallel region. So here, we need to wrap `calc_force`
            // by a `parallel` region.
            local_   .calc_force(sys);
            global_  .calc_force(sys);
            external_.calc_force(sys);
        }
        // merge thread-local forces into master
        sys.merge_forces();
    }
    real_type calc_energy(const system_type& sys) const noexcept
    {
        return local_.calc_energy(sys) + global_.calc_energy(sys) +
            external_.calc_energy(sys);
    }

    std::string list_energy_name() const
    {
        return local_.list_energy() + global_.list_energy() +
            external_.list_energy();
    }
    std::string dump_energy(const system_type& sys) const
    {
        return local_.dump_energy(sys) + global_.dump_energy(sys) +
            external_.dump_energy(sys);
    }

    local_forcefield_type    const& local()    const noexcept {return local_;}
    local_forcefield_type    &      local()          noexcept {return local_;}
    global_forcefield_type   const& global()   const noexcept {return global_;}
    global_forcefield_type   &      global()         noexcept {return global_;}
    external_forcefield_type const& external() const noexcept {return external_;}
    external_forcefield_type &      external()       noexcept {return external_;}

  private:

    local_forcefield_type    local_;
    global_forcefield_type   global_;
    external_forcefield_type external_;
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class ForceField<OpenMPSimulatorTraits<double, UnlimitedBoundary>>;
extern template class ForceField<OpenMPSimulatorTraits<float,  UnlimitedBoundary>>;
extern template class ForceField<OpenMPSimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class ForceField<OpenMPSimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

} // mjolnir
#endif /* MJOLNIR_FORCE_FIELD */
<commit_msg>fix: update interface of ForceField<OpenMP><commit_after>#ifndef MJOLNIR_OMP_FORCE_FIELD_HPP
#define MJOLNIR_OMP_FORCE_FIELD_HPP
#include <mjolnir/core/ForceField.hpp>
#include <mjolnir/omp/System.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT>
class ForceField<OpenMPSimulatorTraits<realT, boundaryT>>
{
  public:
    using traits_type              = OpenMPSimulatorTraits<realT, boundaryT>;
    using real_type                = typename traits_type::real_type;
    using coordinate_type          = typename traits_type::coordinate_type;
    using system_type              = System<traits_type>;
    using local_forcefield_type    = LocalForceField<traits_type>;
    using global_forcefield_type   = GlobalForceField<traits_type>;
    using external_forcefield_type = ExternalForceField<traits_type>;

  public:

    ForceField(local_forcefield_type&& local, global_forcefield_type&& global)
        : local_(std::move(local)), global_(std::move(global))
    {}
    ForceField(local_forcefield_type&&    local,
               global_forcefield_type&&   global,
               external_forcefield_type&& external)
        : local_(std::move(local)), global_(std::move(global)),
          external_(std::move(external))
    {}
    ForceField()  = default;
    ~ForceField() = default;
    ForceField(const ForceField&) = delete;
    ForceField(ForceField&&)      = default;
    ForceField& operator=(const ForceField&) = delete;
    ForceField& operator=(ForceField&&)      = default;

    // this modify system::topology by using local interaction info.
    void initialize(system_type& sys)
    {
        // first, fetch current topology
        local_.write_topology(sys.topology());
        sys.topology().construct_molecules();

        // based on the topology, make exclusion list
        local_   .initialize(sys);
        global_  .initialize(sys);
        external_.initialize(sys);
    }

    // update parameters like temperature, ionic concentration, etc...
    void update(const system_type& sys)
    {
        local_   .update(sys);
        global_  .update(sys);
        external_.update(sys);
    }

    // update margin of neighbor list
    void update_margin(const real_type dmargin, const system_type& sys)
    {
        local_   .update_margin(dmargin, sys);
        global_  .update_margin(dmargin, sys);
        external_.update_margin(dmargin, sys);
    }

    void calc_force(system_type& sys) const noexcept
    {
#pragma omp parallel
        {
            // calc_force uses `nowait` to speedup. To do that, it needs to be
            // inside a parallel region. So here, we need to wrap `calc_force`
            // by a `parallel` region.
            local_   .calc_force(sys);
            global_  .calc_force(sys);
            external_.calc_force(sys);
        }
        // merge thread-local forces into master
        sys.merge_forces();
    }
    real_type calc_energy(const system_type& sys) const noexcept
    {
        return local_.calc_energy(sys) + global_.calc_energy(sys) +
            external_.calc_energy(sys);
    }

    std::vector<std::string> list_energy_name() const
    {
        auto retval = local_.list_energy();
        auto glo    = global_.list_energy();
        auto ext    = external_.list_energy();

        retval.reserve(retval.size() + glo.size() + ext.size());

        std::copy(std::make_move_iterator(glo.begin()),
                  std::make_move_iterator(glo.end()),
                  std::back_inserter(retval));

        std::copy(std::make_move_iterator(ext.begin()),
                  std::make_move_iterator(ext.end()),
                  std::back_inserter(retval));

        return retval;
    }
    std::vector<real_type> dump_energy(const system_type& sys) const
    {
        auto retval = local_.dump_energy(sys);
        auto glo    = global_.dump_energy(sys);
        auto ext    = external_.dump_energy(sys);

        retval.reserve(retval.size() + glo.size() + ext.size());

        std::copy(glo.begin(), glo.end(), std::back_inserter(retval));
        std::copy(ext.begin(), ext.end(), std::back_inserter(retval));
        return retval;
    }

    local_forcefield_type    const& local()    const noexcept {return local_;}
    local_forcefield_type    &      local()          noexcept {return local_;}
    global_forcefield_type   const& global()   const noexcept {return global_;}
    global_forcefield_type   &      global()         noexcept {return global_;}
    external_forcefield_type const& external() const noexcept {return external_;}
    external_forcefield_type &      external()       noexcept {return external_;}

  private:

    local_forcefield_type    local_;
    global_forcefield_type   global_;
    external_forcefield_type external_;
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class ForceField<OpenMPSimulatorTraits<double, UnlimitedBoundary>>;
extern template class ForceField<OpenMPSimulatorTraits<float,  UnlimitedBoundary>>;
extern template class ForceField<OpenMPSimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class ForceField<OpenMPSimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

} // mjolnir
#endif /* MJOLNIR_FORCE_FIELD */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: PaneHider.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 19:02:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include "PaneHider.hxx"

#include "ViewShell.hxx"
#include "ViewShellBase.hxx"
#include "slideshow.hxx"
#include "PaneManager.hxx"

namespace sd {

PaneHider::PaneHider (const ViewShell& rViewShell)
    : mrViewShell(rViewShell),
      mbWindowVisibilitySaved(false),
      mbOriginalLeftPaneWindowVisibility(false),
      mbOriginalRightPaneWindowVisibility(false)
{
    // Hide the left and right pane windows when a slideshow exists and is
    // not full screen.
    Slideshow* pSlideShow = mrViewShell.GetSlideShow();
    if (pSlideShow!=NULL && !pSlideShow->isFullScreen())
    {
        PaneManager& rPaneManager (mrViewShell.GetViewShellBase().GetPaneManager());
        mbOriginalLeftPaneWindowVisibility = rPaneManager.RequestWindowVisibilityChange(
            PaneManager::PT_LEFT,
            false,
            PaneManager::CM_SYNCHRONOUS);
        mbOriginalRightPaneWindowVisibility = rPaneManager.RequestWindowVisibilityChange(
            PaneManager::PT_RIGHT,
            false,
            PaneManager::CM_SYNCHRONOUS);

        mbWindowVisibilitySaved = true;
    }
}

PaneHider::~PaneHider (void)
{
    if (mbWindowVisibilitySaved)
    {
        PaneManager& rPaneManager (mrViewShell.GetViewShellBase().GetPaneManager());
        rPaneManager.RequestWindowVisibilityChange(
            PaneManager::PT_LEFT,
            mbOriginalLeftPaneWindowVisibility,
            PaneManager::CM_ASYNCHRONOUS);
        rPaneManager.RequestWindowVisibilityChange(
            PaneManager::PT_RIGHT,
            mbOriginalRightPaneWindowVisibility,
            PaneManager::CM_ASYNCHRONOUS);
    }
}

} // end of namespace sd
<commit_msg>INTEGRATION: CWS components1 (1.2.396); FILE MERGED 2007/01/24 17:46:26 af 1.2.396.8: #i68075# Introduction of XResourceId interface. 2007/01/22 16:18:31 af 1.2.396.7: #i68075 Introduction of XResourceId interface. 2006/12/08 15:41:05 af 1.2.396.6: #i72399# Catching DisposedException when restoring configuration. 2006/11/22 12:32:04 af 1.2.396.5: #i71253# Optimized how the panes are hidden. 2006/09/25 17:19:06 af 1.2.396.4: RESYNC: (1.2-1.3); FILE MERGED 2006/09/07 14:51:52 af 1.2.396.3: #i68075# Transition from URL to ResourceId. 2006/08/28 14:32:32 af 1.2.396.2: #i68075# Fixed compiler problems. 2006/08/22 11:37:08 af 1.2.396.1: #i68075# Transition to new drawing framework.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: PaneHider.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2007-04-03 16:15:22 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include "PaneHider.hxx"

#include "ViewShell.hxx"
#include "ViewShellBase.hxx"
#include "slideshow.hxx"
#include "framework/FrameworkHelper.hxx"
#include "framework/ConfigurationController.hxx"

#ifndef _COM_SUN_STAR_DRAWING_FRAMEWORK_XCONTROLLERMANAGER_HPP_
#include <com/sun/star/drawing/framework/XControllerManager.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_FRAMEWORK_XPANECONTROLLER_HPP_
#include <com/sun/star/drawing/framework/XPaneController.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_FRAMEWORK_XCONFIGURATIONCONTROLLER_HPP_
#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_FRAMEWORK_XCONFIGURATION_HPP_
#include <com/sun/star/drawing/framework/XConfiguration.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::drawing::framework;
using ::sd::framework::FrameworkHelper;
using ::com::sun::star::lang::DisposedException;

namespace sd {

PaneHider::PaneHider (const ViewShell& rViewShell)
    : mrViewShell(rViewShell),
      mbWindowVisibilitySaved(false),
      mbOriginalLeftPaneWindowVisibility(false),
      mbOriginalRightPaneWindowVisibility(false)
{
    // Hide the left and right pane windows when a slideshow exists and is
    // not full screen.
    Slideshow* pSlideShow = mrViewShell.GetSlideShow();
    if (pSlideShow!=NULL && !pSlideShow->isFullScreen())
    {
        try
        {
            Reference<XControllerManager> xControllerManager (
                mrViewShell.GetViewShellBase().GetController(), UNO_QUERY_THROW);
            mxConfigurationController = xControllerManager->getConfigurationController();
            if (mxConfigurationController.is())
            {
                // Get and save the current configuration.
                mxConfiguration = mxConfigurationController->getConfiguration();
                if (mxConfiguration.is())
                {
                    // Iterate over the resources and deactivate the panes.
                    Sequence<Reference<XResourceId> > aResources (
                        mxConfiguration->getResources(
                            NULL,
                            framework::FrameworkHelper::msPaneURLPrefix,
                            AnchorBindingMode_DIRECT));
                    for (sal_Int32 nIndex=0; nIndex<aResources.getLength(); ++nIndex)
                    {
                        Reference<XResourceId> xPaneId (aResources[nIndex]);
                        if ( ! xPaneId->getResourceURL().equals(FrameworkHelper::msCenterPaneURL))
                        {
                            mxConfigurationController->requestResourceDeactivation(xPaneId);
                        }
                    }
                }
            }
            FrameworkHelper::Instance(mrViewShell.GetViewShellBase())->WaitForUpdate();
        }
        catch (RuntimeException&)
        {
            DBG_ASSERT(false, "caught exception in PaneHider constructor");
        }
    }
}

PaneHider::~PaneHider (void)
{
    if (mxConfiguration.is() && mxConfigurationController.is())
    {
        try
        {
            mxConfigurationController->restoreConfiguration(mxConfiguration);
        }
        catch (DisposedException&)
        {
            // When the configuration controller is already disposed then
            // there is no point in restoring the configuration.
        }
    }
}

} // end of namespace sd
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <Axel.Naumann@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Utils/SourceNormalization.h"

#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"

#include <utility>

using namespace clang;

namespace {
///\brief A Lexer that exposes preprocessor directives.
class MinimalPPLexer: public Lexer {

  ///\brief Jump to last Identifier in a scope chain A::B::C::D
  ///
  bool SkipScopes(Token& Tok) {
    if (getLangOpts().CPlusPlus) {
      while (Tok.is(tok::coloncolon)) {
        if (!LexClean(Tok) || Identifier(Tok).empty())
          return false;
        if (!LexClean(Tok))
          return false;
      }
    }
    return true;
  }

  ///\brief Skips all contiguous '*' '&' tokens
  ///
  bool SkipPointerRefs(Token& Tok) {
    while (Tok.isNot(tok::raw_identifier)) {
      if (!Tok.isOneOf(tok::star, tok::amp))
        return false;
      if (!LexClean(Tok))
        return false;
    }
    return true;
  }

  ///\brief Test if a given token is a valid identifier for the current language
  ///
  /// \param Tok - Token, advanced to first token to test
  /// \return - The valid identifier or empty llvm::StringRef
  llvm::StringRef Identifier(Token& Tok) const {
    if (Tok.is(tok::raw_identifier)) {
      StringRef Id(Tok.getRawIdentifier());
      if (Lexer::isIdentifierBodyChar(Id.front(), getLangOpts()))
        return Id;
    }
    return llvm::StringRef();
  }

public:
  ///\brief Construct a Lexer from LangOpts and source.
  MinimalPPLexer(const LangOptions &LangOpts, llvm::StringRef source):
    Lexer(SourceLocation(), LangOpts,
          source.begin(), source.begin(), source.end()) {}

  bool inPPDirective() const { return ParsingPreprocessorDirective; }

  ///\brief Lex, forwarding to Lexer::LexFromRawLexer, and keeping track of
  /// preprocessor directives to provide a tok::eod corresponding to a
  /// tok::hash.
  bool Lex(Token& Tok) {
    bool ret = LexFromRawLexer(Tok);
    if (inPPDirective()) {
      // Saw a PP directive; probe for eod to end PP parsing mode.
      if (Tok.is(tok::eod))
        ParsingPreprocessorDirective = false;
    } else {
      if (Tok.is(tok::hash)) {
        // Found a PP directive, request tok::eod to be generated.
        ParsingPreprocessorDirective = true;
      }
    }
    return ret;
  }

  ///\brief Advance to token with given token kind.
  ///
  /// \param Tok - Token to advance.
  /// \param kind - Token kind where to stop lexing.
  /// \return - Result of most recent call to Lex().
  bool AdvanceTo(Token& Tok, tok::TokenKind kind) {
    while (!Lex(Tok)) {
      if (Tok.is(kind))
        return false;
    }
    return true;
  }

  ///\brief Lex a token that requires no cleaning
  ///
  /// \return - Result of the lex and whether the token is clean.
  bool LexClean(Token& Tok) {
    if (!LexFromRawLexer(Tok))
      return !Tok.needsCleaning();
    return false;
  }

  ///\brief Make sure a token is closed/balanced properly
  ///
  bool CheckBalance(Token& Tok) {
    const tok::TokenKind In = Tok.getKind();
    const tok::TokenKind Out
      = In == tok::less ? tok::greater : tok::TokenKind(In + 1);
    assert((In == tok::l_paren || In == tok::l_brace || In == tok::l_square
            || In == tok::less) && "Invalid balance token");
    bool atEOF = false;
    int  unBalanced = 1;
    while (unBalanced && !atEOF) {
      atEOF = !LexClean(Tok);
      if (Tok.is(Out))
        --unBalanced;
      else if (Tok.is(In))
        ++unBalanced;
    }
    return unBalanced == 0;
  }

  enum DefinitionType {
    kNONE,     ///< Neither a function or class defintion
    kFunction, ///< Function, method, constructor, or destructor definition
    kClass     ///< Class definition
  };

  ///\brief Test if the given input is a function or class definition
  ///
  /// \param Tok - Token, advanced to first token to test
  /// \param First - First token identifier.
  /// \return - Typeof definition, function/method or class
  DefinitionType IsClassOrFunction(Token& Tok, llvm::StringRef First) {
    /// ###TODO: Allow preprocessor expansion
    if (!Lexer::isIdentifierBodyChar(First.front(), getLangOpts()))
      return kNONE;

    // Early out calling a function/macro Ident()
    if (!LexClean(Tok) || Tok.is(tok::l_paren))
      return kNONE;

    bool Ctor = false;
    if (getLangOpts().CPlusPlus && Tok.is(tok::coloncolon)) {
      // CLASS::CLASS() or CLASS::~CLASS()
      // CLASS::NESTED::NESTED()
      // CLASS::type func()
      // CLASS::NESTED::type Var();
      llvm::StringRef Ident;

      do {
        if (!LexClean(Tok))
          return kNONE;
        if (Tok.is(tok::raw_identifier)) {
          if (!Ident.empty())
            First = Ident;
          Ident = Identifier(Tok);
          if (!LexClean(Tok))
            return kNONE;
          if (Tok.is(tok::less)) {
            // A template: Ident <
            if (!CheckBalance(Tok))
              return kNONE;
            if (!LexClean(Tok))
              return kNONE;
          }
        }
      } while (Tok.is(tok::coloncolon));

      if (Tok.is(tok::tilde)) {
        if (!LexClean(Tok))
          return kNONE;
        if (!Ident.empty())
          First = Ident;
        Ident = Identifier(Tok);

        // Advance to argument list
        if (Ident.empty() || !LexClean(Tok))
          return kNONE;
      } else
        Ctor = true;

      // Constructor and Destructor identifiers must match
      if (!First.equals(Ident)) {
        if (!SkipPointerRefs(Tok))
          return kNONE;

        // Advance to argument list, or next scope
        if (!LexClean(Tok))
          return kNONE;

        // Function name should be last on scope chain
        if (!SkipScopes(Tok))
          return kNONE;

        Ctor = false;
      }
    } else {
      if (First.equals("struct") || First.equals("class")) {
        do {
          // Identifier(Tok).empty() is redundant 1st time, but simplifies code
          if (Identifier(Tok).empty() || !LexClean(Tok))
            return kNONE;
        } while (getLangOpts().CPlusPlus && Tok.is(tok::coloncolon) &&
                 LexClean(Tok));

        // 'class T {' 'struct T {' 'class T :'
        if (Tok.is(tok::l_brace))
          return kClass;
        if (Tok.is(tok::colon))
          return !AdvanceTo(Tok, tok::l_brace) ? kClass : kNONE;

      } else if (First.equals("static") || First.equals("constexpr") ||
                 First.equals("inline") || First.equals("const")) {
        // Advance past keyword for below
        if (!LexClean(Tok))
          return kNONE;
      }

      if (Tok.isNot(tok::raw_identifier)) {
        // If we're not at an identifier, we might be still be in return value:
        // A::B::C funcname() or int * funcname()
        if (!SkipScopes(Tok))
          return kNONE;
        if (!SkipPointerRefs(Tok))
          return kNONE;
      }

      // Function or class name should be in Tok now
      if (Identifier(Tok).empty())
        return kNONE;

      // Advance to argument list or method name
      if (!LexClean(Tok))
        return kNONE;

      if (!SkipScopes(Tok))
        return kNONE;
    }

    // Argument list
    if (Tok.isNot(tok::l_paren))
      return kNONE;

    // ##TODO
    // Lex the argument identifiers so we can know if this is a declaration
    // RVAL IDENT(A,B,C)          -> could be:
    //
    // T inst(a,b,c);            -> class instance
    // T func(T0 a, T1 b, T2 c); -> func declaration
    //
    // Without macro expansion it's difficult to distinguish cases, but as the
    // detection can fail because of macros already, would it be enough to check
    // that there are two idents not separated by commas between parenthesis?
    // It still wouldn't work for RVAL IDENT(), but -Wno-vexing-parse could be
    // passed to clang in initialization.
    //
    // Maybe the best would be to lookup the Decl IDENT to see if its a class?

    if (!CheckBalance(Tok))
      return kNONE;

    if (!LexClean(Tok))
      return kNONE;

    // 'int func() {' or 'CLASS::method() {'
    if (Tok.is(tok::l_brace))
      return kFunction;

    if (getLangOpts().CPlusPlus) {
      // constructor initialization 'CLASS::CLASS() :'
      if (Ctor && Tok.is(tok::colon))
        return !AdvanceTo(Tok, tok::l_brace) ? kFunction : kNONE;

      // class const method 'CLASS::method() const {'
      if (!Ctor && Identifier(Tok).equals("const")) {
        if (LexClean(Tok) && Tok.is(tok::l_brace))
          return kFunction;
      }
    }

    return kNONE;
  }
};

size_t getFileOffset(const Token& Tok) {
  return Tok.getLocation().getRawEncoding();
}

}

size_t
cling::utils::isUnnamedMacro(llvm::StringRef source,
                             clang::LangOptions& LangOpts) {
  // Find the first token that is not a non-cpp directive nor a comment.
  // If that token is a '{' we have an unnamed macro.

  MinimalPPLexer Lex(LangOpts, source);
  Token Tok;
  bool AfterHash = false;
  while (true) {
    bool atEOF = Lex.Lex(Tok);

    if (atEOF)
      return std::string::npos;

    if (Lex.inPPDirective() || Tok.is(tok::eod)) {
      if (AfterHash) {
        if (Tok.is(tok::raw_identifier)) {
          StringRef keyword(Tok.getRawIdentifier());
          if (keyword.startswith("if")) {
            // This could well be
            //   #if FOO
            //   {
            // where we would determine this to be an unnamed macro and replace
            // '{' by ' ', whether FOO is #defined or not. Instead, assume that
            // this is not an unnamed macro and we need to parse it as is.
            return std::string::npos;
          }
        }
        AfterHash = false;
      } else
        AfterHash = Tok.is(tok::hash);

      continue; // Skip PP directives.
    }

    if (Tok.is(tok::l_brace))
      return getFileOffset(Tok);

    if (Tok.is(tok::comment))
      continue; // ignore comments

    return std::string::npos;
  }

  // Empty file?

  return std::string::npos;
}

size_t cling::utils::getWrapPoint(std::string& source,
                                  const clang::LangOptions& LangOpts) {
  // TODO: For future reference.
  // Parser* P = const_cast<clang::Parser*>(m_IncrParser->getParser());
  // Parser::TentativeParsingAction TA(P);
  // TPResult result = P->isCXXDeclarationSpecifier();
  // TA.Revert();
  // return result == TPResult::True();

  MinimalPPLexer Lex(LangOpts, source);
  Token Tok;

  while (true) {
    bool atEOF = Lex.Lex(Tok);
    if (Lex.inPPDirective() || Tok.is(tok::eod)) {
      if (atEOF)
        break;
      continue; // Skip PP directives; they just move the wrap point.
    }

    if (Tok.is(tok::eof)) {
      // Reached EOF before seeing a non-preproc token.
      // Nothing to wrap.
      return std::string::npos;
    }

    // Prior behavior was to return getFileOffset, which was only used as an
    // in a test against std::string::npos. By returning 0 we preserve prior
    // behavior to pass the test against std::string::npos and wrap everything
    const size_t offset = 0;

    // Check, if a function with c++ attributes should be defined.
    while (Tok.getKind() == tok::l_square) {
      Lex.Lex(Tok);
      // Check, if attribute starts with '[['
      if (Tok.getKind() != tok::l_square) {
        return offset;
      }
      // Check, if the second '[' is closing.
      if (!Lex.CheckBalance(Tok)) {
        return offset;
      }
      Lex.Lex(Tok);
      // Check, if the first '[' is closing.
      if (Tok.getKind() != tok::r_square) {
        return offset;
      }
      Lex.Lex(Tok);
    }

    const tok::TokenKind kind = Tok.getKind();

    if (kind == tok::raw_identifier && !Tok.needsCleaning()) {
      StringRef keyword(Tok.getRawIdentifier());
      if (keyword.equals("using")) {
        // FIXME: Using definitions and declarations should be decl extracted.
        // Until we have that, don't wrap them if they are the only input.
        if (Lex.AdvanceTo(Tok, tok::semi)) {
          // EOF while looking for semi. Don't wrap.
          return std::string::npos;
        }
        // There is "more" - let's assume this input consists of a using
        // declaration or definition plus some code that should be wrapped.
        //
        // We need to include the ';' in the offset as this will be a
        // non-wrapped statement.
        return getFileOffset(Tok) + 1;
      }
      if (keyword.equals("extern"))
        return std::string::npos;
      if (keyword.equals("namespace"))
        return std::string::npos;
      if (keyword.equals("template"))
        return std::string::npos;

      if (const MinimalPPLexer::DefinitionType T =
                                          Lex.IsClassOrFunction(Tok, keyword)) {
        assert(Tok.is(tok::l_brace) && "Lexer begin location invalid");
        if (!Lex.CheckBalance(Tok))
          return offset;
        assert(Tok.is(tok::r_brace) && "Lexer end location invalid");

        const size_t rBrace = getFileOffset(Tok);
        // Wrap everything after '}'
        bool atEOF = !Lex.LexClean(Tok);
        bool hadSemi = Tok.is(tok::semi);
        size_t wrapPoint = getFileOffset(Tok);
        if (!atEOF) {
          if (hadSemi) {
            atEOF = !Lex.LexClean(Tok);
            if (!atEOF) {
              // Wrap everything after ';'
              wrapPoint = getFileOffset(Tok);
            }
          } else if (T == MinimalPPLexer::kClass) {
            // 'struct T {} t     '
            // 'struct E {} t = {}'
            // Value print: We want to preserve Tok.is(tok::raw_identifier)
            // unless the statement was terminated by a semi-colon anyway.
            Token Tok2;
            atEOF = Lex.AdvanceTo(Tok2, tok::semi);
            if ((hadSemi = Tok2.is(tok::semi)))
              Tok = Tok2;
          }
        }

        // If nothing left to lex, then don't wrap any of it
        if (atEOF) {
          if (T == MinimalPPLexer::kClass) {
            if (!hadSemi) {
              // Support lack of semi-colon value printing 'struct T {} t'
              if (Tok.is(tok::raw_identifier))
                return 0;
              if (!LangOpts.HeinousExtensions) {
                // Let's fix 'class NoTerminatingSemi { ... }' for them!
                // ### TODO DiagnosticOptions.ShowFixits might be better
                source.insert(rBrace+1, ";");
                return source.size();
              }
            }
          }
          return std::string::npos;
        }

        return wrapPoint;
      }

      // There is something else here that needs to be wrapped.
      return offset;
    }

    // FIXME: in the future, continue lexing to extract relevant PP directives;
    // return wrapPoint
    // There is something else here that needs to be wrapped.
    return offset;
  }

  // We have only had PP directives; no need to wrap.
  return std::string::npos;
}
<commit_msg>Add functionality to SourceNormalization to detect cuda kernels<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <Axel.Naumann@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Utils/SourceNormalization.h"

#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"

#include <utility>

using namespace clang;

namespace {
///\brief A Lexer that exposes preprocessor directives.
class MinimalPPLexer: public Lexer {

  ///\brief Jump to last Identifier in a scope chain A::B::C::D
  ///
  bool SkipScopes(Token& Tok) {
    if (getLangOpts().CPlusPlus) {
      while (Tok.is(tok::coloncolon)) {
        if (!LexClean(Tok) || Identifier(Tok).empty())
          return false;
        if (!LexClean(Tok))
          return false;
      }
    }
    return true;
  }

  ///\brief Skips all contiguous '*' '&' tokens
  ///
  bool SkipPointerRefs(Token& Tok) {
    while (Tok.isNot(tok::raw_identifier)) {
      if (!Tok.isOneOf(tok::star, tok::amp))
        return false;
      if (!LexClean(Tok))
        return false;
    }
    return true;
  }

  ///\brief Test if a given token is a valid identifier for the current language
  ///
  /// \param Tok - Token, advanced to first token to test
  /// \return - The valid identifier or empty llvm::StringRef
  llvm::StringRef Identifier(Token& Tok) const {
    if (Tok.is(tok::raw_identifier)) {
      StringRef Id(Tok.getRawIdentifier());
      if (Lexer::isIdentifierBodyChar(Id.front(), getLangOpts()))
        return Id;
    }
    return llvm::StringRef();
  }

public:
  ///\brief Construct a Lexer from LangOpts and source.
  MinimalPPLexer(const LangOptions &LangOpts, llvm::StringRef source):
    Lexer(SourceLocation(), LangOpts,
          source.begin(), source.begin(), source.end()) {}

  bool inPPDirective() const { return ParsingPreprocessorDirective; }

  ///\brief Lex, forwarding to Lexer::LexFromRawLexer, and keeping track of
  /// preprocessor directives to provide a tok::eod corresponding to a
  /// tok::hash.
  bool Lex(Token& Tok) {
    bool ret = LexFromRawLexer(Tok);
    if (inPPDirective()) {
      // Saw a PP directive; probe for eod to end PP parsing mode.
      if (Tok.is(tok::eod))
        ParsingPreprocessorDirective = false;
    } else {
      if (Tok.is(tok::hash)) {
        // Found a PP directive, request tok::eod to be generated.
        ParsingPreprocessorDirective = true;
      }
    }
    return ret;
  }

  ///\brief Advance to token with given token kind.
  ///
  /// \param Tok - Token to advance.
  /// \param kind - Token kind where to stop lexing.
  /// \return - Result of most recent call to Lex().
  bool AdvanceTo(Token& Tok, tok::TokenKind kind) {
    while (!Lex(Tok)) {
      if (Tok.is(kind))
        return false;
    }
    return true;
  }

  ///\brief Lex a token that requires no cleaning
  ///
  /// \return - Result of the lex and whether the token is clean.
  bool LexClean(Token& Tok) {
    if (!LexFromRawLexer(Tok))
      return !Tok.needsCleaning();
    return false;
  }

  ///\brief Make sure a token is closed/balanced properly
  ///
  bool CheckBalance(Token& Tok) {
    const tok::TokenKind In = Tok.getKind();
    const tok::TokenKind Out
      = In == tok::less ? tok::greater : tok::TokenKind(In + 1);
    assert((In == tok::l_paren || In == tok::l_brace || In == tok::l_square
            || In == tok::less) && "Invalid balance token");
    bool atEOF = false;
    int  unBalanced = 1;
    while (unBalanced && !atEOF) {
      atEOF = !LexClean(Tok);
      if (Tok.is(Out))
        --unBalanced;
      else if (Tok.is(In))
        ++unBalanced;
    }
    return unBalanced == 0;
  }

  enum DefinitionType {
    kNONE,     ///< Neither a function or class defintion
    kFunction, ///< Function, method, constructor, or destructor definition
    kClass     ///< Class definition
  };

  ///\brief Test if the given input is a function or class definition
  ///
  /// \param Tok - Token, advanced to first token to test
  /// \param First - First token identifier.
  /// \return - Typeof definition, function/method or class
  DefinitionType IsClassOrFunction(Token& Tok, llvm::StringRef First) {
    /// ###TODO: Allow preprocessor expansion
    if (!Lexer::isIdentifierBodyChar(First.front(), getLangOpts()))
      return kNONE;

    // Early out calling a function/macro Ident()
    if (!LexClean(Tok) || Tok.is(tok::l_paren))
      return kNONE;

    bool Ctor = false;
    if (getLangOpts().CPlusPlus && Tok.is(tok::coloncolon)) {
      // CLASS::CLASS() or CLASS::~CLASS()
      // CLASS::NESTED::NESTED()
      // CLASS::type func()
      // CLASS::NESTED::type Var();
      llvm::StringRef Ident;

      do {
        if (!LexClean(Tok))
          return kNONE;
        if (Tok.is(tok::raw_identifier)) {
          if (!Ident.empty())
            First = Ident;
          Ident = Identifier(Tok);
          if (!LexClean(Tok))
            return kNONE;
          if (Tok.is(tok::less)) {
            // A template: Ident <
            if (!CheckBalance(Tok))
              return kNONE;
            if (!LexClean(Tok))
              return kNONE;
          }
        }
      } while (Tok.is(tok::coloncolon));

      if (Tok.is(tok::tilde)) {
        if (!LexClean(Tok))
          return kNONE;
        if (!Ident.empty())
          First = Ident;
        Ident = Identifier(Tok);

        // Advance to argument list
        if (Ident.empty() || !LexClean(Tok))
          return kNONE;
      } else
        Ctor = true;

      // Constructor and Destructor identifiers must match
      if (!First.equals(Ident)) {
        if (!SkipPointerRefs(Tok))
          return kNONE;

        // Advance to argument list, or next scope
        if (!LexClean(Tok))
          return kNONE;

        // Function name should be last on scope chain
        if (!SkipScopes(Tok))
          return kNONE;

        Ctor = false;
      }
    } else {
      if (First.equals("struct") || First.equals("class")) {
        do {
          // Identifier(Tok).empty() is redundant 1st time, but simplifies code
          if (Identifier(Tok).empty() || !LexClean(Tok))
            return kNONE;
        } while (getLangOpts().CPlusPlus && Tok.is(tok::coloncolon) &&
                 LexClean(Tok));

        // 'class T {' 'struct T {' 'class T :'
        if (Tok.is(tok::l_brace))
          return kClass;
        if (Tok.is(tok::colon))
          return !AdvanceTo(Tok, tok::l_brace) ? kClass : kNONE;

      } else if (First.equals("static") || First.equals("constexpr") ||
                 First.equals("inline") || First.equals("const")) {
        // Advance past keyword for below
        if (!LexClean(Tok))
          return kNONE;
      }

      if (Tok.isNot(tok::raw_identifier)) {
        // If we're not at an identifier, we might be still be in return value:
        // A::B::C funcname() or int * funcname()
        if (!SkipScopes(Tok))
          return kNONE;
        if (!SkipPointerRefs(Tok))
          return kNONE;
      }

      // Function or class name should be in Tok now
      if (Identifier(Tok).empty())
        return kNONE;

      // Advance to argument list or method name
      if (!LexClean(Tok))
        return kNONE;

      if (!SkipScopes(Tok))
        return kNONE;
    }

    // Argument list
    if (Tok.isNot(tok::l_paren))
      return kNONE;

    // ##TODO
    // Lex the argument identifiers so we can know if this is a declaration
    // RVAL IDENT(A,B,C)          -> could be:
    //
    // T inst(a,b,c);            -> class instance
    // T func(T0 a, T1 b, T2 c); -> func declaration
    //
    // Without macro expansion it's difficult to distinguish cases, but as the
    // detection can fail because of macros already, would it be enough to check
    // that there are two idents not separated by commas between parenthesis?
    // It still wouldn't work for RVAL IDENT(), but -Wno-vexing-parse could be
    // passed to clang in initialization.
    //
    // Maybe the best would be to lookup the Decl IDENT to see if its a class?

    if (!CheckBalance(Tok))
      return kNONE;

    if (!LexClean(Tok))
      return kNONE;

    // 'int func() {' or 'CLASS::method() {'
    if (Tok.is(tok::l_brace))
      return kFunction;

    if (getLangOpts().CPlusPlus) {
      // constructor initialization 'CLASS::CLASS() :'
      if (Ctor && Tok.is(tok::colon))
        return !AdvanceTo(Tok, tok::l_brace) ? kFunction : kNONE;

      // class const method 'CLASS::method() const {'
      if (!Ctor && Identifier(Tok).equals("const")) {
        if (LexClean(Tok) && Tok.is(tok::l_brace))
          return kFunction;
      }
    }

    return kNONE;
  }
};

size_t getFileOffset(const Token& Tok) {
  return Tok.getLocation().getRawEncoding();
}

}

size_t
cling::utils::isUnnamedMacro(llvm::StringRef source,
                             clang::LangOptions& LangOpts) {
  // Find the first token that is not a non-cpp directive nor a comment.
  // If that token is a '{' we have an unnamed macro.

  MinimalPPLexer Lex(LangOpts, source);
  Token Tok;
  bool AfterHash = false;
  while (true) {
    bool atEOF = Lex.Lex(Tok);

    if (atEOF)
      return std::string::npos;

    if (Lex.inPPDirective() || Tok.is(tok::eod)) {
      if (AfterHash) {
        if (Tok.is(tok::raw_identifier)) {
          StringRef keyword(Tok.getRawIdentifier());
          if (keyword.startswith("if")) {
            // This could well be
            //   #if FOO
            //   {
            // where we would determine this to be an unnamed macro and replace
            // '{' by ' ', whether FOO is #defined or not. Instead, assume that
            // this is not an unnamed macro and we need to parse it as is.
            return std::string::npos;
          }
        }
        AfterHash = false;
      } else
        AfterHash = Tok.is(tok::hash);

      continue; // Skip PP directives.
    }

    if (Tok.is(tok::l_brace))
      return getFileOffset(Tok);

    if (Tok.is(tok::comment))
      continue; // ignore comments

    return std::string::npos;
  }

  // Empty file?

  return std::string::npos;
}

size_t cling::utils::getWrapPoint(std::string& source,
                                  const clang::LangOptions& LangOpts) {
  // TODO: For future reference.
  // Parser* P = const_cast<clang::Parser*>(m_IncrParser->getParser());
  // Parser::TentativeParsingAction TA(P);
  // TPResult result = P->isCXXDeclarationSpecifier();
  // TA.Revert();
  // return result == TPResult::True();

  MinimalPPLexer Lex(LangOpts, source);
  Token Tok;

  while (true) {
    bool atEOF = Lex.Lex(Tok);
    if (Lex.inPPDirective() || Tok.is(tok::eod)) {
      if (atEOF)
        break;
      continue; // Skip PP directives; they just move the wrap point.
    }

    if (Tok.is(tok::eof)) {
      // Reached EOF before seeing a non-preproc token.
      // Nothing to wrap.
      return std::string::npos;
    }

    // detect the attribute (__global__, __device__ and __host__) of CUDA
    // kernels at the beginning of a function definition
    // FIXME: should replaced by a generic solution
    if (LangOpts.CUDA) {
      do {
        if (Tok.getKind() == tok::raw_identifier) {
          StringRef keyword(Tok.getRawIdentifier());
          if (keyword.equals("__global__") || keyword.equals("__device__") ||
              keyword.equals("__host__"))
            // if attribute was found, skip the token and use the function
            // detection later
            Lex.Lex(Tok);
          else
            break;
        } else
          break;
      } while (true);
    }

    // Prior behavior was to return getFileOffset, which was only used as an
    // in a test against std::string::npos. By returning 0 we preserve prior
    // behavior to pass the test against std::string::npos and wrap everything
    const size_t offset = 0;

    // Check, if a function with c++ attributes should be defined.
    while (Tok.getKind() == tok::l_square) {
      Lex.Lex(Tok);
      // Check, if attribute starts with '[['
      if (Tok.getKind() != tok::l_square) {
        return offset;
      }
      // Check, if the second '[' is closing.
      if (!Lex.CheckBalance(Tok)) {
        return offset;
      }
      Lex.Lex(Tok);
      // Check, if the first '[' is closing.
      if (Tok.getKind() != tok::r_square) {
        return offset;
      }
      Lex.Lex(Tok);
    }

    const tok::TokenKind kind = Tok.getKind();

    if (kind == tok::raw_identifier && !Tok.needsCleaning()) {
      StringRef keyword(Tok.getRawIdentifier());
      if (keyword.equals("using")) {
        // FIXME: Using definitions and declarations should be decl extracted.
        // Until we have that, don't wrap them if they are the only input.
        if (Lex.AdvanceTo(Tok, tok::semi)) {
          // EOF while looking for semi. Don't wrap.
          return std::string::npos;
        }
        // There is "more" - let's assume this input consists of a using
        // declaration or definition plus some code that should be wrapped.
        //
        // We need to include the ';' in the offset as this will be a
        // non-wrapped statement.
        return getFileOffset(Tok) + 1;
      }
      if (keyword.equals("extern"))
        return std::string::npos;
      if (keyword.equals("namespace"))
        return std::string::npos;
      if (keyword.equals("template"))
        return std::string::npos;

      if (const MinimalPPLexer::DefinitionType T =
                                          Lex.IsClassOrFunction(Tok, keyword)) {
        assert(Tok.is(tok::l_brace) && "Lexer begin location invalid");
        if (!Lex.CheckBalance(Tok))
          return offset;
        assert(Tok.is(tok::r_brace) && "Lexer end location invalid");

        const size_t rBrace = getFileOffset(Tok);
        // Wrap everything after '}'
        bool atEOF = !Lex.LexClean(Tok);
        bool hadSemi = Tok.is(tok::semi);
        size_t wrapPoint = getFileOffset(Tok);
        if (!atEOF) {
          if (hadSemi) {
            atEOF = !Lex.LexClean(Tok);
            if (!atEOF) {
              // Wrap everything after ';'
              wrapPoint = getFileOffset(Tok);
            }
          } else if (T == MinimalPPLexer::kClass) {
            // 'struct T {} t     '
            // 'struct E {} t = {}'
            // Value print: We want to preserve Tok.is(tok::raw_identifier)
            // unless the statement was terminated by a semi-colon anyway.
            Token Tok2;
            atEOF = Lex.AdvanceTo(Tok2, tok::semi);
            if ((hadSemi = Tok2.is(tok::semi)))
              Tok = Tok2;
          }
        }

        // If nothing left to lex, then don't wrap any of it
        if (atEOF) {
          if (T == MinimalPPLexer::kClass) {
            if (!hadSemi) {
              // Support lack of semi-colon value printing 'struct T {} t'
              if (Tok.is(tok::raw_identifier))
                return 0;
              if (!LangOpts.HeinousExtensions) {
                // Let's fix 'class NoTerminatingSemi { ... }' for them!
                // ### TODO DiagnosticOptions.ShowFixits might be better
                source.insert(rBrace+1, ";");
                return source.size();
              }
            }
          }
          return std::string::npos;
        }

        return wrapPoint;
      }

      // There is something else here that needs to be wrapped.
      return offset;
    }

    // FIXME: in the future, continue lexing to extract relevant PP directives;
    // return wrapPoint
    // There is something else here that needs to be wrapped.
    return offset;
  }

  // We have only had PP directives; no need to wrap.
  return std::string::npos;
}
<|endoftext|>


<commit_before>/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

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

#include <GG/adobe/future/widgets/headers/platform_checkbox.hpp>

#include <GG/adobe/future/widgets/headers/widget_utils.hpp>

#include <GG/adobe/future/widgets/headers/platform_metrics.hpp>
#include <GG/adobe/future/widgets/headers/display.hpp>

#include <GG/Button.h>
#include <GG/GUI.h>
#include <GG/StyleFactory.h>

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

namespace {

struct Checked
{
    Checked(adobe::checkbox_t& checkbox) :
        m_checkbox(checkbox)
        {}
    void operator()(bool checked)
        {
            m_checkbox.hit_proc_m(checked ?
                                  adobe::any_regular_t(m_checkbox.true_value_m) :
                                  adobe::any_regular_t(m_checkbox.false_value_m));
        }
    adobe::checkbox_t& m_checkbox;
};

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

} // namespace

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

namespace adobe {

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

checkbox_t::checkbox_t( const std::string&                      name,
                        const any_regular_t&                    true_value,
                        const any_regular_t&                    false_value,
                        theme_t                                 theme,
                        const std::string&                      alt_text) :
    control_m(0),
    theme_m(theme),
    true_value_m(true_value),
    false_value_m(false_value),
    name_m(name),
    alt_text_m(alt_text)
{ }

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

void checkbox_t::measure(extents_t& result)
{
    GG::Pt min_usable_size = control_m->MinUsableSize();

    result.width() = Value(min_usable_size.x);
    result.height() = Value(min_usable_size.y);

    result.vertical().guide_set_m.push_back(
        Value((min_usable_size.y - implementation::DefaultFont()->Lineskip()) / 2 +
              implementation::DefaultFont()->Ascent())
    );
}

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

void checkbox_t::place(const place_data_t& place_data)
{
    assert(control_m);
    implementation::set_control_bounds(control_m, place_data);
}

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

void checkbox_t::enable(bool make_enabled)
{
    if (control_m)
        control_m->Disable(!make_enabled);
}

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

void checkbox_t::display(const any_regular_t& new_value)
{
    assert(control_m);

    if (current_value_m == new_value) return;

    current_value_m = new_value;

    if (current_value_m == true_value_m)
        control_m->SetCheck(true);
    else if (current_value_m == false_value_m)
        control_m->SetCheck(true);
    else
        assert(!"checkbox_t::display() : non-true and non-false value set");
}

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

void checkbox_t::monitor(const setter_type& proc)
{
    assert(control_m);

    hit_proc_m = proc;
}

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

template <>
platform_display_type insert<checkbox_t>(display_t&             display,
                                         platform_display_type& parent,
                                         checkbox_t&            element)
{
    assert(element.control_m == 0);

    element.control_m =
        implementation::Factory().NewStateButton(GG::X0, GG::Y0, GG::X1, implementation::StandardHeight(),
                                                 element.name_m, implementation::DefaultFont(),
                                                 GG::CLR_GRAY);

    GG::Connect(element.control_m->CheckedSignal, Checked(element));

    if (!element.alt_text_m.empty())
        adobe::implementation::set_control_alt_text(element.control_m, element.alt_text_m);

    return display.insert(parent, element.control_m);
}

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

} // namespace adobe

/****************************************************************************************************/
<commit_msg>Fixed checkbox_t::display().<commit_after>/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

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

#include <GG/adobe/future/widgets/headers/platform_checkbox.hpp>

#include <GG/adobe/future/widgets/headers/widget_utils.hpp>

#include <GG/adobe/future/widgets/headers/platform_metrics.hpp>
#include <GG/adobe/future/widgets/headers/display.hpp>

#include <GG/Button.h>
#include <GG/GUI.h>
#include <GG/StyleFactory.h>

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

namespace {

struct Checked
{
    Checked(adobe::checkbox_t& checkbox) :
        m_checkbox(checkbox)
        {}
    void operator()(bool checked)
        {
            m_checkbox.hit_proc_m(checked ?
                                  adobe::any_regular_t(m_checkbox.true_value_m) :
                                  adobe::any_regular_t(m_checkbox.false_value_m));
        }
    adobe::checkbox_t& m_checkbox;
};

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

} // namespace

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

namespace adobe {

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

checkbox_t::checkbox_t( const std::string&                      name,
                        const any_regular_t&                    true_value,
                        const any_regular_t&                    false_value,
                        theme_t                                 theme,
                        const std::string&                      alt_text) :
    control_m(0),
    theme_m(theme),
    true_value_m(true_value),
    false_value_m(false_value),
    name_m(name),
    alt_text_m(alt_text)
{ }

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

void checkbox_t::measure(extents_t& result)
{
    GG::Pt min_usable_size = control_m->MinUsableSize();

    result.width() = Value(min_usable_size.x);
    result.height() = Value(min_usable_size.y);

    result.vertical().guide_set_m.push_back(
        Value((min_usable_size.y - implementation::DefaultFont()->Lineskip()) / 2 +
              implementation::DefaultFont()->Ascent())
    );
}

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

void checkbox_t::place(const place_data_t& place_data)
{
    assert(control_m);
    implementation::set_control_bounds(control_m, place_data);
}

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

void checkbox_t::enable(bool make_enabled)
{
    if (control_m)
        control_m->Disable(!make_enabled);
}

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

void checkbox_t::display(const any_regular_t& new_value)
{
    assert(control_m);

    if (current_value_m == new_value) return;

    current_value_m = new_value;

    if (current_value_m == true_value_m)
        control_m->SetCheck(true);
    else if (current_value_m == false_value_m)
        control_m->SetCheck(false);
    else
        assert(!"checkbox_t::display() : non-true and non-false value set");
}

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

void checkbox_t::monitor(const setter_type& proc)
{
    assert(control_m);

    hit_proc_m = proc;
}

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

template <>
platform_display_type insert<checkbox_t>(display_t&             display,
                                         platform_display_type& parent,
                                         checkbox_t&            element)
{
    assert(element.control_m == 0);

    element.control_m =
        implementation::Factory().NewStateButton(GG::X0, GG::Y0, GG::X1, implementation::StandardHeight(),
                                                 element.name_m, implementation::DefaultFont(),
                                                 GG::CLR_GRAY);

    GG::Connect(element.control_m->CheckedSignal, Checked(element));

    if (!element.alt_text_m.empty())
        adobe::implementation::set_control_alt_text(element.control_m, element.alt_text_m);

    return display.insert(parent, element.control_m);
}

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

} // namespace adobe

/****************************************************************************************************/
<|endoftext|>


<commit_before>/*  This file is part of the Vc project
    Copyright (C) 2009-2010 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

*/

#include <Vc/Vc>
#include <Vc/IO>
#include <iostream>
#include <iomanip>
#include <valarray>
#include "../tsc.h"
#include "common/macros.h"

static constexpr int UnrollOuterloop = 4;

template <typename T, size_t N> class MatrixValarray
{
    using V = std::valarray<T>;
    V data[N];

public:
    MatrixValarray()
    {
        for (auto &v : data) {
            v.resize(N);
        }
    }
    std::valarray<T> &operator[](std::size_t i) { return data[i]; }
    const std::valarray<T> &operator[](std::size_t i) const { return data[i]; }
};

template <typename T, size_t N>
inline MatrixValarray<T, N> operator*(const MatrixValarray<T, N> &a,
                                      const MatrixValarray<T, N> &b)
{
    MatrixValarray<T, N> c;
    for (size_t i = 0; i < N; ++i) {
        c[i] = a[i][0] * b[0];
        for (size_t k = 1; k < N; ++k) {
            c[i] += a[i][k] * b[k];
        }
    }
    return c;
}

template <typename T, size_t N> class Matrix
{
    using V = Vc::Vector<T>;

    // round up to the next multiple of V::size()
    static constexpr size_t NPadded = (N + V::size() - 1) / V::size() * V::size();

    // the inner array stores one row of values and is padded
    using RowArray = std::array<T, NPadded>;

    // The following function is a workaround for GCC 4.8, which fails to recognize
    // V::MemoryAlignment as a constant expression inside the alignas operator.
    static constexpr size_t dataAlignment() { return V::MemoryAlignment; }
    // The outer array stores N rows and does not require further padding. It must be
    // aligned correctly for Vc::Aligned loads and stores, though.
    alignas(dataAlignment()) std::array<RowArray, N> data;

public:
    Matrix()
    {
        for (int i = 0; i < int(N); ++i) {
            for (int j = N; j < int(NPadded); ++j) {
                data[i][j] = 0;
            }
        }
    }
    // returns a reference to the i-th row
    RowArray &operator[](size_t i) { return data[i]; }
    // const overload of the above
    const RowArray &operator[](size_t i) const { return data[i]; }
};

// vectorized matrix multiplication
template <typename T, size_t N>
inline Matrix<T, N> operator*(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    constexpr int NN = N;
    using V = Vc::Vector<T>;
    // resulting matrix c
    Matrix<T, N> c;

    // The row index (for a and c) is unrolled using the UnrollOuterloop stride. Therefore
    // the last rows may need special treatment if N is not a multiple of UnrollOuterloop.
    // N0 is the number of rows that can safely be iterated with a stride of
    // UnrollOuterloop.
    constexpr int N0 = N / UnrollOuterloop * UnrollOuterloop;
    for (int i = 0; i < N0; i += UnrollOuterloop) {
        // The iteration over the column index of b and c uses a stride of V::size(). This
        // enables row-vector loads (from b) and stores (to c). The matrix storage is
        // padded accordingly, ensuring correct bounds and alignment.
        for (int j = 0; j < NN; j += V::size()) {
            // This temporary variables are used to accumulate the results of the products
            // producing the new values for the c matrix. This variable is necessary
            // because we need a V object for data-parallel accumulation. Storing to c
            // directly stores to scalar objects and thus would drop the ability for
            // data-parallel (SIMD) addition.
            V c_ij[UnrollOuterloop];
            for (int n = 0; n < UnrollOuterloop; ++n) {
                c_ij[n] = a[i + n][0] * V(&b[0][j], Vc::Aligned);
            }
            for (int k = 1; k < NN - 1; ++k) {
                for (int n = 0; n < UnrollOuterloop; ++n) {
                    c_ij[n] += a[i + n][k] * V(&b[k][j], Vc::Aligned);
                }
            }
            for (int n = 0; n < UnrollOuterloop; ++n) {
                c_ij[n] += a[i + n][NN - 1] * V(&b[NN - 1][j], Vc::Aligned);
                c_ij[n].store(&c[i + n][j], Vc::Aligned);
            }
        }
    }
    // This final loop treats the remaining NN - N0 rows.
    for (int j = 0; j < NN; j += V::size()) {
        V c_ij[UnrollOuterloop];
        for (int n = N0; n < NN; ++n) {
            c_ij[n - N0] = a[n][0] * V(&b[0][j], Vc::Aligned);
        }
        for (int k = 1; k < NN - 1; ++k) {
            for (int n = N0; n < NN; ++n) {
                c_ij[n - N0] += a[n][k] * V(&b[k][j], Vc::Aligned);
            }
        }
        for (int n = N0; n < NN; ++n) {
            c_ij[n - N0] += a[n][NN - 1] * V(&b[N - 1][j], Vc::Aligned);
            c_ij[n - N0].store(&c[n][j], Vc::Aligned);
        }
    }
    return c;
}

// scalar matrix multiplication
template <typename T, size_t N>
Matrix<T, N> scalar_mul(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    constexpr int NN = N;
    Matrix<T, N> c;
    for (int i = 0; i < NN; ++i) {
        for (int j = 0; j < NN; ++j) {
            c[i][j] = a[i][0] * b[0][j];
            for (int k = 1; k < NN; ++k) {
                c[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    return c;
}

// scalar matrix multiplication
template <typename T, size_t N>
Matrix<T, N> scalar_mul_blocked(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    constexpr int NN = N;
    Matrix<T, N> c;
    constexpr int N0 = N / UnrollOuterloop * UnrollOuterloop;
    for (int i = 0; i < N0; i += UnrollOuterloop) {
        for (int j = 0; j < NN; ++j) {
            for (int n = 0; n < UnrollOuterloop; ++n) {
                c[i + n][j] = a[i + n][0] * b[0][j];
            }
            for (int k = 1; k < NN; ++k) {
                for (int n = 0; n < UnrollOuterloop; ++n) {
                    c[i + n][j] += a[i + n][k] * b[k][j];
                }
            }
        }
    }
    for (int j = 0; j < NN; ++j) {
        for (int n = N0; n < NN; ++n) {
            c[n][j] = a[n][0] * b[0][j];
        }
        for (int k = 1; k < NN; ++k) {
            for (int n = N0; n < NN; ++n) {
                c[n][j] += a[n][k] * b[k][j];
            }
        }
    }
    return c;
}

// valarray matrix multiplication
template <typename T, size_t N>
Matrix<T, N> valarray_mul(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    Matrix<T, N> c;
    using V = std::valarray<T>;
    for (size_t i = 0; i < N; ++i) {
        V c_i = a[i][0] * V(&b[0][0], N);
        for (size_t k = 1; k < N; ++k) {
            c_i += a[i][k] * V(&b[k][0], N);
        }
        std::copy(std::begin(c_i), std::end(c_i), &c[i][0]);
    }
    return c;
}

template <template <typename, size_t> class M, typename T, size_t N,
          typename = Vc::enable_if<(std::is_same<M<T, N>, Matrix<T, N>>::value ||
                                    std::is_same<M<T, N>, MatrixValarray<T, N>>::value)>>
std::ostream &operator<<(std::ostream &out, const M<T, N> &m)
{
    out.precision(3);
    auto &&w = std::setw(6);
    out << "⎡" << w << m[0][0];
    for (size_t j = 1; j < N; ++j) {
        out << ", " << w << m[0][j];
    }
    out << " ⎤\n";
    for (size_t i = 1; i + 1 < N; ++i) {
        out << "⎢" << w << m[i][0];
        for (size_t j = 1; j < N; ++j) {
            out << ", " << w << m[i][j];
        }
        out << " ⎥\n";
    }
    out << "⎣" << w << m[N - 1][0];
    for (size_t j = 1; j < N; ++j) {
        out << ", " << w << m[N - 1][j];
    }
    return out << " ⎦\n";
}

template <typename T> void unused(T &&x) { asm("" ::"m"(x)); }

template <size_t N, typename F> Vc_ALWAYS_INLINE void benchmark(F &&f)
{
    TimeStampCounter tsc;
    auto cycles = tsc.cycles();
    cycles = 0x7fffffff;
    for (int i = 0; i < 100; ++i) {
        tsc.start();
        for (int j = 0; j < 10; ++j) {
            auto C = f();
            unused(C);
        }
        tsc.stop();
        cycles = std::min(cycles, tsc.cycles());
    }
    //std::cout << cycles << " Cycles for " << N *N *(N + N - 1) << " FLOP => ";
    std::cout << std::setw(19) << std::setprecision(3)
              << double(N * N * (N + N - 1) * 10) / cycles;
    //<< " FLOP/cycle (" << variant << ")\n";
}

template <size_t N> void run()
{
    Matrix<float, N> A;
    Matrix<float, N> B;
    MatrixValarray<float, N> AV;
    MatrixValarray<float, N> BV;
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = 0; j < N; ++j) {
            A[i][j] = 0.01 * (i + j);
            B[i][j] = 0.01 * (N + i - j);
            AV[i][j] = 0.01 * (i + j);
            BV[i][j] = 0.01 * (N + i - j);
        }
    }
    std::cout << std::setw(2) << N;
    benchmark<N>([&] {
        asm("" : "+m"(A), "+m"(B));
        return scalar_mul(A, B);
    });
    benchmark<N>([&] {
        asm("" : "+m"(A), "+m"(B));
        return scalar_mul_blocked(A, B);
    });
    benchmark<N>([&] {
        asm("" : "+m"(A), "+m"(B));
        return A * B;
    });
    benchmark<N>([&] {
        asm("" : "+m"(AV), "+m"(BV));
        return AV * BV;
    });
    std::cout << std::endl;
}

int main()
{
    std::cout << " N             scalar   scalar & blocked          Vector<T>           valarray\n";
    run< 4>();
    run< 5>();
    run< 6>();
    run< 7>();
    run< 8>();
    run< 9>();
    run<10>();
    run<11>();
    run<12>();
    run<13>();
    run<14>();
    run<15>();
    run<16>();
    run<17>();
    run<18>();
    run<19>();
    run<20>();
    run<21>();
    run<22>();
    run<23>();
    run<24>();
    run<25>();
    run<26>();
    run<27>();
    run<28>();
    run<29>();
    run<30>();
    run<31>();
    run<32>();
    run<33>();
    run<34>();
    run<35>();
    return 0;
}
<commit_msg>Matrix: work around ICC limitation<commit_after>/*  This file is part of the Vc project
    Copyright (C) 2009-2010 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

*/

#include <Vc/Vc>
#include <Vc/IO>
#include <iostream>
#include <iomanip>
#include <valarray>
#include "../tsc.h"
#include "common/macros.h"

static constexpr int UnrollOuterloop = 4;

template <typename T, size_t N> class MatrixValarray
{
    using V = std::valarray<T>;
    V data[N];

public:
    MatrixValarray()
    {
        for (auto &v : data) {
            v.resize(N);
        }
    }
    std::valarray<T> &operator[](std::size_t i) { return data[i]; }
    const std::valarray<T> &operator[](std::size_t i) const { return data[i]; }
};

template <typename T, size_t N>
inline MatrixValarray<T, N> operator*(const MatrixValarray<T, N> &a,
                                      const MatrixValarray<T, N> &b)
{
    MatrixValarray<T, N> c;
    for (size_t i = 0; i < N; ++i) {
        c[i] = a[i][0] * b[0];
        for (size_t k = 1; k < N; ++k) {
            c[i] += a[i][k] * b[k];
        }
    }
    return c;
}

template <typename T, size_t N> class Matrix
{
    using V = Vc::Vector<T>;

    // round up to the next multiple of V::size()
    static constexpr size_t NPadded = (N + V::size() - 1) / V::size() * V::size();

    // the inner array stores one row of values and is padded
    using RowArray = std::array<T, NPadded>;

    // The following function is a workaround for GCC 4.8, which fails to recognize
    // V::MemoryAlignment as a constant expression inside the alignas operator.
    static constexpr size_t dataAlignment() { return V::MemoryAlignment; }
    // The outer array stores N rows and does not require further padding. It must be
    // aligned correctly for Vc::Aligned loads and stores, though.
    alignas(dataAlignment()) std::array<RowArray, N> data;

public:
    Matrix()
    {
        for (int i = 0; i < int(N); ++i) {
            for (int j = N; j < int(NPadded); ++j) {
                data[i][j] = 0;
            }
        }
    }
    // returns a reference to the i-th row
    RowArray &operator[](size_t i) { return data[i]; }
    // const overload of the above
    const RowArray &operator[](size_t i) const { return data[i]; }
};

// vectorized matrix multiplication
template <typename T, size_t N>
inline Matrix<T, N> operator*(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    constexpr int NN = N;
    using V = Vc::Vector<T>;
    // resulting matrix c
    Matrix<T, N> c;

    // The row index (for a and c) is unrolled using the UnrollOuterloop stride. Therefore
    // the last rows may need special treatment if N is not a multiple of UnrollOuterloop.
    // N0 is the number of rows that can safely be iterated with a stride of
    // UnrollOuterloop.
    constexpr int N0 = N / UnrollOuterloop * UnrollOuterloop;
    for (int i = 0; i < N0; i += UnrollOuterloop) {
        // The iteration over the column index of b and c uses a stride of V::size(). This
        // enables row-vector loads (from b) and stores (to c). The matrix storage is
        // padded accordingly, ensuring correct bounds and alignment.
        for (int j = 0; j < NN; j += V::size()) {
            // This temporary variables are used to accumulate the results of the products
            // producing the new values for the c matrix. This variable is necessary
            // because we need a V object for data-parallel accumulation. Storing to c
            // directly stores to scalar objects and thus would drop the ability for
            // data-parallel (SIMD) addition.
            V c_ij[UnrollOuterloop];
            for (int n = 0; n < UnrollOuterloop; ++n) {
                c_ij[n] = a[i + n][0] * V(&b[0][j], Vc::Aligned);
            }
            for (int k = 1; k < NN - 1; ++k) {
                for (int n = 0; n < UnrollOuterloop; ++n) {
                    c_ij[n] += a[i + n][k] * V(&b[k][j], Vc::Aligned);
                }
            }
            for (int n = 0; n < UnrollOuterloop; ++n) {
                c_ij[n] += a[i + n][NN - 1] * V(&b[NN - 1][j], Vc::Aligned);
                c_ij[n].store(&c[i + n][j], Vc::Aligned);
            }
        }
    }
    // This final loop treats the remaining NN - N0 rows.
    for (int j = 0; j < NN; j += V::size()) {
        V c_ij[UnrollOuterloop];
        for (int n = N0; n < NN; ++n) {
            c_ij[n - N0] = a[n][0] * V(&b[0][j], Vc::Aligned);
        }
        for (int k = 1; k < NN - 1; ++k) {
            for (int n = N0; n < NN; ++n) {
                c_ij[n - N0] += a[n][k] * V(&b[k][j], Vc::Aligned);
            }
        }
        for (int n = N0; n < NN; ++n) {
            c_ij[n - N0] += a[n][NN - 1] * V(&b[N - 1][j], Vc::Aligned);
            c_ij[n - N0].store(&c[n][j], Vc::Aligned);
        }
    }
    return c;
}

// scalar matrix multiplication
template <typename T, size_t N>
Matrix<T, N> scalar_mul(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    constexpr int NN = N;
    Matrix<T, N> c;
    for (int i = 0; i < NN; ++i) {
        for (int j = 0; j < NN; ++j) {
            c[i][j] = a[i][0] * b[0][j];
            for (int k = 1; k < NN; ++k) {
                c[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    return c;
}

// scalar matrix multiplication
template <typename T, size_t N>
Matrix<T, N> scalar_mul_blocked(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    constexpr int NN = N;
    Matrix<T, N> c;
    constexpr int N0 = N / UnrollOuterloop * UnrollOuterloop;
    for (int i = 0; i < N0; i += UnrollOuterloop) {
        for (int j = 0; j < NN; ++j) {
            for (int n = 0; n < UnrollOuterloop; ++n) {
                c[i + n][j] = a[i + n][0] * b[0][j];
            }
            for (int k = 1; k < NN; ++k) {
                for (int n = 0; n < UnrollOuterloop; ++n) {
                    c[i + n][j] += a[i + n][k] * b[k][j];
                }
            }
        }
    }
    for (int j = 0; j < NN; ++j) {
        for (int n = N0; n < NN; ++n) {
            c[n][j] = a[n][0] * b[0][j];
        }
        for (int k = 1; k < NN; ++k) {
            for (int n = N0; n < NN; ++n) {
                c[n][j] += a[n][k] * b[k][j];
            }
        }
    }
    return c;
}

// valarray matrix multiplication
template <typename T, size_t N>
Matrix<T, N> valarray_mul(const Matrix<T, N> &a, const Matrix<T, N> &b)
{
    Matrix<T, N> c;
    using V = std::valarray<T>;
    for (size_t i = 0; i < N; ++i) {
        V c_i = a[i][0] * V(&b[0][0], N);
        for (size_t k = 1; k < N; ++k) {
            c_i += a[i][k] * V(&b[k][0], N);
        }
        std::copy(std::begin(c_i), std::end(c_i), &c[i][0]);
    }
    return c;
}

template <template <typename, size_t> class M, typename T, size_t N,
          typename = Vc::enable_if<(std::is_same<M<T, N>, Matrix<T, N>>::value ||
                                    std::is_same<M<T, N>, MatrixValarray<T, N>>::value)>>
std::ostream &operator<<(std::ostream &out, const M<T, N> &m)
{
    out.precision(3);
    auto &&w = std::setw(6);
    out << "⎡" << w << m[0][0];
    for (size_t j = 1; j < N; ++j) {
        out << ", " << w << m[0][j];
    }
    out << " ⎤\n";
    for (size_t i = 1; i + 1 < N; ++i) {
        out << "⎢" << w << m[i][0];
        for (size_t j = 1; j < N; ++j) {
            out << ", " << w << m[i][j];
        }
        out << " ⎥\n";
    }
    out << "⎣" << w << m[N - 1][0];
    for (size_t j = 1; j < N; ++j) {
        out << ", " << w << m[N - 1][j];
    }
    return out << " ⎦\n";
}

template <typename T> void unused(T &&x) { asm("" ::"m"(x)); }

template <size_t N, typename F> Vc_ALWAYS_INLINE void benchmark(F &&f)
{
    TimeStampCounter tsc;
    auto cycles = tsc.cycles();
    cycles = 0x7fffffff;
    for (int i = 0; i < 100; ++i) {
        tsc.start();
        for (int j = 0; j < 10; ++j) {
            auto C = f();
            unused(C);
        }
        tsc.stop();
        cycles = std::min(cycles, tsc.cycles());
    }
    //std::cout << cycles << " Cycles for " << N *N *(N + N - 1) << " FLOP => ";
    std::cout << std::setw(19) << std::setprecision(3)
              << double(N * N * (N + N - 1) * 10) / cycles;
    //<< " FLOP/cycle (" << variant << ")\n";
}

template <size_t N> void run()
{
    Matrix<float, N> A;
    Matrix<float, N> B;
    MatrixValarray<float, N> AV;
    MatrixValarray<float, N> BV;
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = 0; j < N; ++j) {
            A[i][j] = 0.01 * (i + j);
            B[i][j] = 0.01 * (N + i - j);
            AV[i][j] = 0.01 * (i + j);
            BV[i][j] = 0.01 * (N + i - j);
        }
    }
    std::cout << std::setw(2) << N;
    benchmark<N>([&] {
#ifdef VC_ICC
        asm("" :: "r"(&A), "r"(&B));
#else
        asm("" : "+m"(A), "+m"(B));
#endif
        return scalar_mul(A, B);
    });
    benchmark<N>([&] {
#ifdef VC_ICC
        asm("" :: "r"(&A), "r"(&B));
#else
        asm("" : "+m"(A), "+m"(B));
#endif
        return scalar_mul_blocked(A, B);
    });
    benchmark<N>([&] {
#ifdef VC_ICC
        asm("" :: "r"(&A), "r"(&B));
#else
        asm("" : "+m"(A), "+m"(B));
#endif
        return A * B;
    });
    benchmark<N>([&] {
#ifdef VC_ICC
        asm("" :: "r"(&A), "r"(&B));
#else
        asm("" : "+m"(A), "+m"(B));
#endif
        return AV * BV;
    });
    std::cout << std::endl;
}

int main()
{
    std::cout << " N             scalar   scalar & blocked          Vector<T>           valarray\n";
    run< 4>();
    run< 5>();
    run< 6>();
    run< 7>();
    run< 8>();
    run< 9>();
    run<10>();
    run<11>();
    run<12>();
    run<13>();
    run<14>();
    run<15>();
    run<16>();
    run<17>();
    run<18>();
    run<19>();
    run<20>();
    run<21>();
    run<22>();
    run<23>();
    run<24>();
    run<25>();
    run<26>();
    run<27>();
    run<28>();
    run<29>();
    run<30>();
    run<31>();
    run<32>();
    run<33>();
    run<34>();
    run<35>();
    return 0;
}
<|endoftext|>


<commit_before>/*
** Copyright 2011-2012 Merethis
**
** This file is part of Centreon Clib.
**
** Centreon Clib 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.
**
** Centreon Clib 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 Centreon Clib. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <string.h>
#include "com/centreon/exceptions/basic.hh"
#include "com/centreon/misc/command_line.hh"

using namespace com::centreon::misc;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
command_line::command_line()
  : _argc(0), _argv(NULL), _size(0) {}

/**
 *  Parse command line.
 *
 *  @param[in] cmdline  The command line to parse.
 */
command_line::command_line(std::string const& cmdline)
  : _argc(0), _argv(NULL), _size(0) {
  parse(cmdline);
}

/**
 *  Copy constructor.
 *
 *  @param[in] right  The object to copy.
 */
command_line::command_line(command_line const& right)
  : _argv(NULL) {
  _internal_copy(right);
}

/**
 *  Destructor.
 */
command_line::~command_line() throw () {
  _release();
}

/**
 *  Copy operator.
 *
 *  @param[in] right  The object to copy.
 *
 *  @return This object.
 */
command_line& command_line::operator=(command_line const& right) {
  return (_internal_copy(right));
}

/**
 *  Equal operator.
 *
 *  @param[in] right  The object to compare.
 *
 *  @return True if objects are equal, otherwise false.
 */
bool command_line::operator==(command_line const& right) const throw () {
  return (_argc == right._argc
          && _size == right._size
          && !memcmp(_argv[0], right._argv[0], _size));
}

/**
 *  Not equal operator.
 *
 *  @param[in] right  The object to compare.
 *
 *  @return True if objects are not equal, otherwise false.
 */
bool command_line::operator!=(command_line const& right) const throw () {
  return (!operator==(right));
}

/**
 *  Get the size array of arguments.
 *
 *  @return Size.
 */
int command_line::get_argc() const throw () {
  return (_argc);
}

/**
 *  Get the array of arguments.
 *
 *  @return Array arguments.
 */
char** command_line::get_argv() const throw () {
  return (_argv);
}

/**
 *  Parse command line and store arguments.
 *
 *  @param[in] cmdline  The command line to parse.
 */
void command_line::parse(std::string const& cmdline) {
  _release();

  char* str(new char[cmdline.size() + 1]);
  _size = 0;
  str[_size] = 0;

  bool escap(false);
  char sep(0);
  char last(0);
  for (size_t i(0), end(cmdline.size()); i < end; ++i) {
    char c(cmdline[i]);
    escap = (last == '\\' ? !escap : false);
    if (!sep && isblank(c)) {
      if (last && !isblank(last) && str[_size - 1]) {
        str[_size++] = 0;
        ++_argc;
      }
    }
    else if (!escap && (c == '\'' || c == '"')) {
      if (!sep)
        sep = c;
      else if (sep == c) {
        str[_size++] = 0;
        ++_argc;
        sep = 0;
      }
      else if (c != '\\' || (escap && c == last))
        str[_size++] = c;
    }
    else if (escap) {
      switch (c) {
      case 'n':
        c = '\n';
        break ;
      case 'r':
        c = '\r';
        break ;
      case 't':
        c = '\t';
        break ;
      }
      str[_size++] = c;
    }
    else if (c != '\\')
      str[_size++] = c;
    last = c;
  }

  if (sep) {
    delete[] str;
    throw (basic_error() << "missing separator '" << sep << "'");
  }

  if (last && _size && str[_size - 1]) {
    str[_size] = 0;
    ++_argc;
  }

  _size = 0;
  _argv = new char*[_argc + 1];
  _argv[_argc] = NULL;
  for (int i(0); i < _argc; ++i) {
    _argv[i] = str + _size;
    while (str[_size++]);
  }

  if (!_argv[0])
    delete[] str;
}

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Internal copy.
 *
 *  @param[in] right  The object to copy.
 *
 *  @return This object.
 */
command_line& command_line::_internal_copy(command_line const& right) {
  if (this != &right) {
    _argc = right._argc;
    _size = right._size;
    _release();
    if (right._argv) {
      _argv = new char*[_argc + 1];
      _argv[0] = new char[_size];
      _argv[_argc] = NULL;
      memcpy(_argv[0], right._argv[0], _size);
      unsigned int pos(0);
      for (int i(0); i < _argc; ++i) {
        _argv[i] = _argv[0] + pos;
        while (_argv[0][pos++]);
      }
    }
  }
  return (*this);
}

/**
 *  Release memory used.
 */
void command_line::_release() {
  if (_argv)
    delete[] _argv[0];
  delete[] _argv;
  _argv = NULL;
}
<commit_msg>Handle escaped characters in command line parsing.<commit_after>/*
** Copyright 2011-2012 Merethis
**
** This file is part of Centreon Clib.
**
** Centreon Clib 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.
**
** Centreon Clib 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 Centreon Clib. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <string.h>
#include "com/centreon/exceptions/basic.hh"
#include "com/centreon/misc/command_line.hh"

using namespace com::centreon::misc;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
command_line::command_line()
  : _argc(0), _argv(NULL), _size(0) {}

/**
 *  Parse command line.
 *
 *  @param[in] cmdline  The command line to parse.
 */
command_line::command_line(std::string const& cmdline)
  : _argc(0), _argv(NULL), _size(0) {
  parse(cmdline);
}

/**
 *  Copy constructor.
 *
 *  @param[in] right  The object to copy.
 */
command_line::command_line(command_line const& right)
  : _argv(NULL) {
  _internal_copy(right);
}

/**
 *  Destructor.
 */
command_line::~command_line() throw () {
  _release();
}

/**
 *  Copy operator.
 *
 *  @param[in] right  The object to copy.
 *
 *  @return This object.
 */
command_line& command_line::operator=(command_line const& right) {
  _internal_copy(right);
  return (*this);
}

/**
 *  Equal operator.
 *
 *  @param[in] right  The object to compare.
 *
 *  @return True if objects are equal, otherwise false.
 */
bool command_line::operator==(command_line const& right) const throw () {
  return (_argc == right._argc
          && _size == right._size
          && !memcmp(_argv[0], right._argv[0], _size));
}

/**
 *  Not equal operator.
 *
 *  @param[in] right  The object to compare.
 *
 *  @return True if objects are not equal, otherwise false.
 */
bool command_line::operator!=(command_line const& right) const throw () {
  return (!operator==(right));
}

/**
 *  Get the size array of arguments.
 *
 *  @return Size.
 */
int command_line::get_argc() const throw () {
  return (_argc);
}

/**
 *  Get the array of arguments.
 *
 *  @return Array arguments.
 */
char** command_line::get_argv() const throw () {
  return (_argv);
}

/**
 *  Parse command line and store arguments.
 *
 *  @param[in] cmdline  The command line to parse.
 */
void command_line::parse(std::string const& cmdline) {
  // Allocate buffer.
  _release();
  char* str(new char[cmdline.size() + 1]);
  _size = 0;
  str[_size] = 0;

  // Status variables.
  bool escap(false);
  char sep(0);
  char last(0);
  for (size_t i(0), end(cmdline.size()); i < end; ++i) {
    // Current processed char.
    char c(cmdline[i]);

    // Is this an escaped character ?
    escap = (last == '\\' ? !escap : false);
    if (escap) {
      switch (c) {
      case 'n':
        c = '\n';
        break ;
      case 'r':
        c = '\r';
        break ;
      case 't':
        c = '\t';
        break ;
      }
    }

    // End of token.
    if (!sep && isblank(c)) {
      if (last && !isblank(last) && str[_size - 1]) {
        str[_size++] = 0;
        ++_argc;
      }
    }
    // Quotes.
    else if (!escap && (c == '\'' || c == '"')) {
      if (!sep)
        sep = c;
      else if (sep == c) {
        str[_size++] = 0;
        ++_argc;
        sep = 0;
      }
      else if ((c != '\\') || escap)
        str[_size++] = c;
    }
    // Normal char (backslashes are used for escaping).
    else if ((c != '\\') || escap)
      str[_size++] = c;
    last = c;
  }

  // Not-terminated quote.
  if (sep) {
    delete [] str;
    throw (basic_error() << "missing separator '" << sep << "'");
  }

  // Terminate string if not already done so.
  if (last && _size && str[_size - 1]) {
    str[_size] = 0;
    ++_argc;
  }

  // Put tokens in table.
  _size = 0;
  _argv = new char*[_argc + 1];
  _argv[_argc] = NULL;
  for (int i(0); i < _argc; ++i) {
    _argv[i] = str + _size;
    while (str[_size++]);
  }

  // If no token were found, avoid memory leak.
  if (!_argv[0])
    delete [] str;

  return ;
}

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Internal copy.
 *
 *  @param[in] right  The object to copy.
 *
 *  @return This object.
 */
command_line& command_line::_internal_copy(command_line const& right) {
  if (this != &right) {
    _argc = right._argc;
    _size = right._size;
    _release();
    if (right._argv) {
      _argv = new char*[_argc + 1];
      _argv[0] = new char[_size];
      _argv[_argc] = NULL;
      memcpy(_argv[0], right._argv[0], _size);
      unsigned int pos(0);
      for (int i(0); i < _argc; ++i) {
        _argv[i] = _argv[0] + pos;
        while (_argv[0][pos++]);
      }
    }
  }
  return (*this);
}

/**
 *  Release memory used.
 */
void command_line::_release() {
  if (_argv)
    delete [] _argv[0];
  delete [] _argv;
  _argv = NULL;
  return ;
}
<|endoftext|>