text: //*****************************************************************************
  // Copyright 2017-2020 Intel Corporation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //*****************************************************************************
  
  #pragma once
  
  #include <list>
  #include <memory>
  #include <vector>
  
  #include "ngraph/deprecated.hpp"
  #include "ngraph/function.hpp"
  #include "ngraph/node.hpp"
  #include "ngraph/util.hpp"
  
  namespace ngraph
  {
      namespace pass
      {
          using param_callback = std::function<bool(const std::shared_ptr<const ::ngraph::Node>)>;
          using param_callback_map = std::map<ngraph::DiscreteTypeInfo, param_callback>;
  
          /// \brief Class representing a transformations config that is used for disabling/enabling
          /// transformations registered inside pass::Manager and also allows to set callback for all
          /// transformations or for particular transformation.
          ///
          /// When pass::Manager is created all passes registered inside this manager including nested
          /// passes will share the same instance of PassConfig class.
          /// To work with this class first you need to get shared instance of this class by calling
          /// manager.get_pass_config() method. Then you will be able to disable/enable passes based
          /// on transformations type_info. For example:
          ///
          ///     pass::Manager manager;
          ///     manager.register_pass<CommonOptimizations>();
          ///     auto pass_config = manager.get_pass_config();
          ///     pass_config->disable<ConvertGELU>(); // this will disable nested pass inside
          ///                                          // CommonOptimizations pipeline
          ///     manager.run_passes(f);
          ///
          /// Sometimes it is needed to call transformation inside other transformation manually. And
          /// for that case before running transformation you need manually check that this pass is
          /// not disabled and then you need to set current PassConfig instance to this
          /// transformation. For example:
          ///
          ///     // Inside MatcherPass callback or inside FunctionPass run_on_function() method
          ///     // you need to call get_pass_config() method to get shared instance of PassConfig
          ///     auto pass_config = get_pass_config();
          ///
          ///     // Before running nested transformation you need to check is it disabled or not
          ///     if (!pass_config->is_disabled<ConvertGELU>()) {
          ///         auto pass = ConvertGELU();
          ///         pass->set_pass_config(pass_config);
          ///         pass.apply(node);
          ///     }
          ///
          /// Following this logic inside your transformations you will guaranty that transformations
          /// will be executed in a right way.
          class NGRAPH_API PassConfig
          {
          public:
              /// \brief Disable transformation by its type_info
              /// \param type_info Transformation type_info
              void disable(const DiscreteTypeInfo& type_info);
              /// \brief Disable transformation by its class type (based on type_info)
              template <typename T>
              void disable()
              {
                  disable(T::type_info);
              }
  
              /// \brief Enable transformation by its type_info
              /// \param type_info Transformation type_info
              void enable(const DiscreteTypeInfo& type_info);
              /// \brief Enable transformation by its class type (based on type_info)
              template <typename T>
              void enable()
              {
                  enable(T::type_info);
              }
  
              /// \brief Set callback for all kind of transformations
              void set_callback(const param_callback& callback) { m_callback = callback; }
              template <typename... Args>
              typename std::enable_if<sizeof...(Args) == 0>::type
                  set_callback(const param_callback& callback)
              {
              }
  
              /// \brief Set callback for particular transformation class types
              ///
              /// Example below show how to set callback for one or multiple passes using this method.
              ///
              ///     pass_config->set_callback<ngraph::pass::ConvertBatchToSpace,
              ///                               ngraph::pass::ConvertSpaceToBatch>(
              ///              [](const_node_ptr &node) -> bool {
              ///                   // Disable transformations for cases when input shape rank is not
              ///                   equal to 4
              ///                   const auto input_shape_rank =
              ///                   node->get_output_partial_shape(0).rank().get_length();
              ///                   if (input_shape_rank != 4) {
              ///                       return false;
              ///                   }
              ///                   return true;
              ///               });
              ///
              /// Note that inside transformations you must provide code that work with this callback.
              /// See example below:
              ///
              ///     if (transformation_callback(node)) {
              ///         return false; // exit from transformation
              ///     }
              ///
              template <typename T, class... Args>
              void set_callback(const param_callback& callback)
              {
                  m_callback_map[T::type_info] = callback;
                  set_callback<Args...>(callback);
              }
  
              /// \brief Get callback for given transformation type_info
              /// \param type_info Transformation type_info
              ///
              /// In case if callback wasn't set for given transformation type then global callback
              /// will be returned. But if even global callback wasn't set then default callback will
              /// be returned.
              param_callback get_callback(const DiscreteTypeInfo& type_info) const;
  
              /// \brief Get callback for given transformation class type
              /// \return callback lambda function
              template <typename T>
              param_callback get_callback() const
              {
                  return get_callback(T::type_info);
              }
  
              /// \brief Check either transformation type is disabled or not
              /// \param type_info Transformation type_info
              /// \return true if transformation type was disabled and false otherwise
              bool is_disabled(const DiscreteTypeInfo& type_info) const
              {
                  return m_disabled.count(type_info);
              }
  
              /// \brief Check either transformation class type is disabled or not
              /// \return true if transformation type was disabled and false otherwise
              template <typename T>
              bool is_disabled() const
              {
                  return is_disabled(T::type_info);
              }
  
              /// \brief Check either transformation type is force enabled or not
              /// \param type_info Transformation type_info
              /// \return true if transformation type was force enabled and false otherwise
              bool is_enabled(const DiscreteTypeInfo& type_info) const
              {
                  return m_enabled.count(type_info);
              }
  
              /// \brief Check either transformation class type is force enabled or not
              /// \return true if transformation type was force enabled and false otherwise
              template <typename T>
              bool is_enabled() const
              {
                  return is_enabled(T::type_info);
              }
  
              void add_disabled_passes(const PassConfig& rhs);
  
          private:
              param_callback m_callback = [](const std::shared_ptr<const ::ngraph::Node>&) {
                  return false;
              };
              param_callback_map m_callback_map;
              std::unordered_set<DiscreteTypeInfo> m_disabled;
              std::unordered_set<DiscreteTypeInfo> m_enabled;
          };
      }
  }