<commit_before>#pragma once
#include <PluginFactory/details/NullPluginService.hpp>
#include <PluginFactory/details/PluginHandle.hpp>
#include <PluginFactory/details/PolicyHolder.hpp>
#include <PluginFactory/details/PolicyProperties.hpp>
#include <PluginFactory/Exceptions.hpp>

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

namespace PluginFactory {

    // A tag type to indicate we want to create a shared_ptr to
    struct AsSharedTagType {};

    // <PluginInterface> is the abstract interface of the plugin object itself. You'll need
    // a PluginFactory for each different type of plugin you wish to support.
    //
    // <PluginServiceInterface> is the interface given to the plugin to allow it to make
    // modifications to the main program. This is to encourage plugin developers not to
    // engage in crazy behavior like calling willy-nilly into the base process's code.
    //
    // NOTE: lifetime management using plugins can be difficult. It is essential
    // the PluginFactory stays in scope longer than any instanced plugin.
    template<class PluginInterface, class PluginServiceInterface = details::NullPluginService, class PolicyOwnershipProperty = details::PolicyIsInternal>
    class PluginFactory : public details::PolicyHolder<PluginServiceInterface, PolicyOwnershipProperty>
    {
    public:
        static AsSharedTagType create_shared;

        // @pluginDirectory is the directory path to load plugins from.
        template<typename... Args>
        PluginFactory(const boost::filesystem::path& pluginDirectory, Args&&... args);

        void load();        // load all found plugins
        void load(const boost::filesystem::path& pluginPath);   // load a specific plugin (@pluginPath)

        void unload();      // unload all loaded plugins
        void unload(const boost::filesystem::path& pluginPath); // unload a specific plugin (@pluginPath)

        std::unique_ptr<PluginInterface> instance(const std::string& plugin);
        std::shared_ptr<PluginInterface> instance(const std::string& pluginName, AsSharedTagType /*create_shared*/);

        std::vector<std::string> availablePlugins() const;

    private:
        using PluginPath = std::string;
        using PluginInstanceMethod = std::function<PluginInterface* (PluginServiceInterface&)>;
        std::unordered_map<PluginPath, PluginHandle<PluginInterface, PluginServiceInterface>> plugins_;

        boost::filesystem::path pluginDirectory_;
    };

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    template<typename... Args>
    PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::PluginFactory(const boost::filesystem::path& pluginDirectory, Args&&... args)
        : details::PolicyHolder<PluginServiceInterface, PolicyOwnershipProperty>(std::forward<Args>(args)...)
        , pluginDirectory_(pluginDirectory)
    {
        if(!boost::filesystem::exists(pluginDirectory_))
        {
            throw PluginPathDoesntExist(pluginDirectory_);
        }

        if(!boost::filesystem::is_directory(pluginDirectory_))
        {
            throw PluginPathIsntDirectory(pluginDirectory_);
        }
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::load()
    {
        // [ARG]: TODO: implement
        // iterate over the directory collecting all shared libs (dylib on mac, so on linux, dll/DLL on windows)
        //
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::load(const boost::filesystem::path& pluginPath)
    {
        // [ARG]: TODO: implement
        // load the plugin
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::unload()
    {
        plugins_.clear();
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::unload(const boost::filesystem::path& pluginPath)
    {
        auto iter = plugins_.find(pluginPath.string());
        if(iter != plugins_.end())
        {
            plugins_.erase(iter);
        }
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    std::unique_ptr<PluginInterface> PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::instance(const std::string& pluginName)
    {
        std::unique_ptr<PluginInterface> p;

        auto iter = plugins_.find(pluginName);
        if(iter != plugins_.end())
        {
            auto& createPlugin = iter->second;
            p.reset(createPlugin(this->policy_));
        }

        return p;
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    std::shared_ptr<PluginInterface> PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::instance(const std::string& pluginName, AsSharedTagType)
    {
        std::shared_ptr<PluginInterface> p;

        auto iter = plugins_.find(pluginName);
        if(iter != plugins_.end())
        {
            auto& createPlugin = iter->second;
            p.reset(createPlugin(this->policy_));
        }

        return p;
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    std::vector<std::string> PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::availablePlugins() const
    {
        std::vector<std::string> plugins;
        plugins.reserve(plugins_.size());

        for(const auto& info : plugins_)
        {
            const auto& key = info.first;
            plugins.push_back(key);
        }

        return plugins;
    }
}
<commit_msg>comments: improvements.<commit_after>#pragma once
#include <PluginFactory/details/NullPluginService.hpp>
#include <PluginFactory/details/PluginHandle.hpp>
#include <PluginFactory/details/PolicyHolder.hpp>
#include <PluginFactory/details/PolicyProperties.hpp>
#include <PluginFactory/Exceptions.hpp>

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

namespace PluginFactory {

    // A tag type to indicate we want to create a shared_ptr to
    struct AsSharedTagType {};

    // <PluginInterface> is the abstract interface of the plugin object itself. You'll need
    // a PluginFactory for each different type of plugin you wish to support.
    //
    // <PluginServiceInterface> is the interface given to the plugin to allow it to make
    // modifications to the main program. This is to encourage plugin developers not to
    // engage in crazy behavior like calling willy-nilly into the base process's code.
    //
    // NOTE: lifetime management using plugins can be difficult. It is essential
    // the PluginFactory stays in scope longer than any instanced plugin. Failure
    // to do so will most likely end in the process crashing.
    template<class PluginInterface, class PluginServiceInterface = details::NullPluginService, class PolicyOwnershipProperty = details::PolicyIsInternal>
    class PluginFactory : public details::PolicyHolder<PluginServiceInterface, PolicyOwnershipProperty>
    {
    public:
        static AsSharedTagType create_shared;

        // @pluginDirectory is the directory path to load plugins from.
        template<typename... Args>
        PluginFactory(const boost::filesystem::path& pluginDirectory, Args&&... args);

        void load();        // load all found plugins
        void load(const boost::filesystem::path& pluginPath);   // load a specific plugin (@pluginPath)

        void unload();      // unload all loaded plugins
        void unload(const boost::filesystem::path& pluginPath); // unload a specific plugin (@pluginPath)

        std::unique_ptr<PluginInterface> instance(const std::string& plugin);
        std::shared_ptr<PluginInterface> instance(const std::string& pluginName, AsSharedTagType /*create_shared*/);

        std::vector<std::string> availablePlugins() const;

    private:
        using PluginPath = std::string;
        using PluginInstanceMethod = std::function<PluginInterface* (PluginServiceInterface&)>;
        std::unordered_map<PluginPath, PluginHandle<PluginInterface, PluginServiceInterface>> plugins_;

        boost::filesystem::path pluginDirectory_;
    };

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    template<typename... Args>
    PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::PluginFactory(const boost::filesystem::path& pluginDirectory, Args&&... args)
        : details::PolicyHolder<PluginServiceInterface, PolicyOwnershipProperty>(std::forward<Args>(args)...)
        , pluginDirectory_(pluginDirectory)
    {
        if(!boost::filesystem::exists(pluginDirectory_))
        {
            throw PluginPathDoesntExist(pluginDirectory_);
        }

        if(!boost::filesystem::is_directory(pluginDirectory_))
        {
            throw PluginPathIsntDirectory(pluginDirectory_);
        }
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::load()
    {
        // [ARG]: TODO: implement
        // iterate over the directory collecting all shared libs (dylib on mac, so on linux, dll/DLL on windows)
        //
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::load(const boost::filesystem::path& pluginPath)
    {
        // [ARG]: TODO: implement
        // load the plugin
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::unload()
    {
        plugins_.clear();
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    void PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::unload(const boost::filesystem::path& pluginPath)
    {
        auto iter = plugins_.find(pluginPath.string());
        if(iter != plugins_.end())
        {
            plugins_.erase(iter);
        }
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    std::unique_ptr<PluginInterface> PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::instance(const std::string& pluginName)
    {
        std::unique_ptr<PluginInterface> p;

        auto iter = plugins_.find(pluginName);
        if(iter != plugins_.end())
        {
            auto& createPlugin = iter->second;
            p.reset(createPlugin(this->policy_));
        }

        return p;
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    std::shared_ptr<PluginInterface> PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::instance(const std::string& pluginName, AsSharedTagType)
    {
        std::shared_ptr<PluginInterface> p;

        auto iter = plugins_.find(pluginName);
        if(iter != plugins_.end())
        {
            auto& createPlugin = iter->second;
            p.reset(createPlugin(this->policy_));
        }

        return p;
    }

    template<class PluginInterface, class PluginServiceInterface, class PolicyOwnershipProperty>
    std::vector<std::string> PluginFactory<PluginInterface, PluginServiceInterface, PolicyOwnershipProperty>::availablePlugins() const
    {
        std::vector<std::string> plugins;
        plugins.reserve(plugins_.size());

        for(const auto& info : plugins_)
        {
            const auto& key = info.first;
            plugins.push_back(key);
        }

        return plugins;
    }
}
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/tf2xla/kernels/if_op.h"

#include "tensorflow/compiler/tf2xla/shape_util.h"
#include "tensorflow/compiler/tf2xla/xla_context.h"
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"

namespace tensorflow {

XlaIfOp::XlaIfOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) {
  const NameAttrList* name_attr;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("then_branch", &name_attr));
  then_branch_ = *name_attr;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("else_branch", &name_attr));
  else_branch_ = *name_attr;

  OP_REQUIRES_OK(ctx, ctx->GetAttr("Tcond", &cond_type_));
  OP_REQUIRES_OK(ctx, ctx->GetAttr("Tin", &input_types_));
  OP_REQUIRES_OK(ctx, ctx->GetAttr("Tout", &output_types_));
}

// TODO(b/35949885): There is duplication here with the handling of the
// while_op. Refactor the common code out/rework.
void XlaIfOp::Compile(XlaOpKernelContext* ctx) {
  xla::XlaBuilder* b = ctx->builder();

  OP_REQUIRES(ctx, cond_type_ == DT_BOOL,
              errors::InvalidArgument(
                  "Condition argument must be a boolean for XLA compilation"));
  OP_REQUIRES(ctx, TensorShapeUtils::IsScalar(ctx->InputShape(0)),
              errors::InvalidArgument(
                  "Condition argument must be a scalar for XLA compilation"));

  VLOG(1) << "Building If: " << input_types_.size() << " inputs";

  std::vector<XlaCompiler::Argument> arguments(input_types_.size());
  for (int i = 0; i < input_types_.size(); ++i) {
    XlaCompiler::Argument& arg = arguments[i];
    DataType type = ctx->input_type(i + 1);

    if (type == DT_RESOURCE) {
      XlaResource* resource;
      OP_REQUIRES_OK(ctx, ctx->GetResourceInput(i + 1, &resource));

      arg.initialized = resource->initialized();
      arg.kind = XlaCompiler::Argument::kResource;
      arg.resource_kind = resource->kind();

      arg.type = resource->type();
      arg.shape = resource->shape();
      OP_REQUIRES(ctx, arg.initialized,
                  errors::Unimplemented("Uninitialized arguments: ", arg.name));
      arg.tensor_array_size = resource->tensor_array_size();
      for (const auto& gradient : resource->tensor_array_gradients()) {
        arg.tensor_array_gradients.insert(gradient.first);
      }
      arg.name = resource->name();
      VLOG(2) << "Resource " << resource->name()
              << " type: " << DataTypeString(arg.type)
              << " shape: " << arg.shape.DebugString()
              << " initialized: " << arg.initialized;
    } else {
      arg.kind = XlaCompiler::Argument::kParameter;
      arg.type = input_types_[i];
      arg.shape = ctx->InputShape(i + 1);
      VLOG(2) << "Arg type: " << DataTypeString(arg.type)
              << " shape: " << arg.shape.DebugString();
    }
  }

  // Compile both branches of the conditional.
  XlaCompiler::CompileOptions options;
  options.use_tuple_arg = true;
  options.resolve_compile_time_constants = false;
  options.return_updated_values_for_all_resources = true;
  options.is_entry_computation = false;
  XlaCompiler* compiler = ctx->compiler();

  XlaCompiler::CompilationResult then_result;
  OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, then_branch_,
                                                arguments, &then_result));
  XlaCompiler::CompilationResult else_result;
  OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, else_branch_,
                                                arguments, &else_result));

  bool has_tensor_array_gradients = false;
  for (XlaCompiler::CompilationResult* result : {&then_result, &else_result}) {
    for (const XlaCompiler::ResourceUpdate& update : result->resource_updates) {
      XlaResource* resource;
      OP_REQUIRES_OK(ctx,
                     ctx->GetResourceInput(update.input_index + 1, &resource));
      XlaCompiler::Argument& arg = arguments[update.input_index];

      // Add any TensorArray gradients touched by the then/else computation to
      // the enclosing graph.
      for (const string& grad_source : update.tensor_array_gradients_accessed) {
        VLOG(5) << "TensorArray " << resource->name() << " accessed gradient "
                << grad_source;
        XlaResource* gradient;
        OP_REQUIRES_OK(ctx, resource->GetOrCreateTensorArrayGradient(
                                grad_source, b, &gradient));
      }
      // Add all of the TensorArray gradients to the argument. For simplicity,
      // we always pass all known gradients.
      for (const auto& gradient : resource->tensor_array_gradients()) {
        arg.tensor_array_gradients.insert(gradient.first);
      }
      if (!resource->tensor_array_gradients().empty())
        has_tensor_array_gradients = true;
    }
  }

  // Recompile the functions to update the argument shapes for tensor arrays.
  if (has_tensor_array_gradients) {
    then_result = {};
    OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, then_branch_,
                                                  arguments, &then_result));
    else_result = {};
    OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, else_branch_,
                                                  arguments, &else_result));
  }

  // Check that both branches have identical input shapes.
  OP_REQUIRES(ctx, then_result.xla_input_shapes.size() == 1,
              errors::FailedPrecondition("Expected one input shape"));
  xla::Shape then_input_shape = then_result.xla_input_shapes[0];
  OP_REQUIRES(ctx, xla::ShapeUtil::IsTuple(then_input_shape),
              errors::FailedPrecondition("Expected tuple shape"));
  OP_REQUIRES(ctx, else_result.xla_input_shapes.size() == 1,
              errors::FailedPrecondition("Expected one input shape"));
  xla::Shape else_input_shape = else_result.xla_input_shapes[0];
  OP_REQUIRES(ctx, xla::ShapeUtil::IsTuple(else_input_shape),
              errors::FailedPrecondition("Expected tuple shape"));
  OP_REQUIRES(ctx,
              xla::ShapeUtil::Compatible(then_input_shape, else_input_shape),
              errors::InvalidArgument(
                  "Input shapes of then and else branches do not match: ",
                  xla::ShapeUtil::HumanString(then_input_shape), " vs. ",
                  xla::ShapeUtil::HumanString(else_input_shape)));

  // Check that both branches have identical output shapes.
  OP_REQUIRES(
      ctx,
      xla::ShapeUtil::Compatible(then_result.xla_output_shape,
                                 else_result.xla_output_shape),
      errors::InvalidArgument(
          "Output shapes of then and else branches do not match: ",
          xla::ShapeUtil::HumanString(then_result.xla_output_shape), " vs. ",
          xla::ShapeUtil::HumanString(else_result.xla_output_shape)));

  VLOG(2) << "Input shape: " << xla::ShapeUtil::HumanString(then_input_shape);
  VLOG(2) << "Output shape: "
          << xla::ShapeUtil::HumanString(then_result.xla_output_shape);

  // We set return_updated_values_for_all_resources=true and we pass the same
  // arguments to both computations, so the resource update count must match.
  OP_REQUIRES(ctx,
              then_result.resource_updates.size() ==
                  else_result.resource_updates.size(),
              errors::FailedPrecondition(
                  "Different number of resources in then and else branch"));
  for (int i = 0; i < then_result.resource_updates.size(); ++i) {
    const auto& lhs = then_result.resource_updates[i];
    const auto& rhs = else_result.resource_updates[i];
    bool equal = lhs.input_index == rhs.input_index && lhs.shape == rhs.shape &&
                 lhs.tensor_array_gradients_accessed ==
                     rhs.tensor_array_gradients_accessed;
    OP_REQUIRES(
        ctx, equal,
        errors::FailedPrecondition(
            "Mismatch in resource of then and else branch for resource ", i));
  }

  int num_inputs = then_result.input_mapping.size();
  std::vector<xla::XlaOp> inputs(num_inputs);
  for (int i = 0; i < num_inputs; ++i) {
    int input_num = then_result.input_mapping[i] + 1;
    if (ctx->input_type(input_num) == DT_RESOURCE) {
      XlaResource* resource;
      OP_REQUIRES_OK(ctx, ctx->GetResourceInput(input_num, &resource));
      OP_REQUIRES_OK(ctx, resource->Pack(&inputs[i], b));
    } else {
      inputs[i] = ctx->Input(i + 1);
    }
  }

  xla::XlaOp outputs = xla::Conditional(
      ctx->Input(0), xla::Tuple(b, inputs), *then_result.computation,
      xla::Tuple(b, inputs), *else_result.computation);
  // Sets non-variable outputs.
  for (int i = 0; i < output_types_.size(); ++i) {
    if (ctx->input_type(i) != DT_RESOURCE) {
      xla::XlaOp output_handle = xla::GetTupleElement(outputs, i);
      if (VLOG_IS_ON(2)) {
        LOG(INFO) << "Setting output " << i;
        auto shape_or = b->GetShape(output_handle);
        if (shape_or.ok()) {
          LOG(INFO) << "Shape for output " << i << ": "
                    << xla::ShapeUtil::HumanString(shape_or.ValueOrDie());
        } else {
          LOG(INFO) << "Shape unknown for output " << i;
        }
      }
      ctx->SetOutput(i, output_handle);
    }
  }

  // Updates the values of any resource variables modified by the conditional
  // bodies.
  for (XlaCompiler::CompilationResult* result : {&then_result, &else_result}) {
    for (int i = 0; i < result->resource_updates.size(); ++i) {
      const XlaCompiler::ResourceUpdate& update = result->resource_updates[i];
      XlaResource* resource;
      OP_REQUIRES_OK(ctx,
                     ctx->GetResourceInput(update.input_index + 1, &resource));
      if (update.modified) {
        int pos = result->outputs.size() + i;
        OP_REQUIRES_OK(ctx,
                       resource->SetFromPack(
                           arguments[update.input_index].tensor_array_gradients,
                           xla::GetTupleElement(outputs, pos), b));
      }
      VLOG(2) << "If variable: pos: " << update.input_index
              << " name: " << resource->name()
              << " modified: " << update.modified
              << " type: " << DataTypeString(update.type)
              << " shape: " << update.shape.DebugString();
    }
  }
  VLOG(1) << "Done building If";
}

REGISTER_XLA_OP(Name("If").AllowResourceTypes(), XlaIfOp);
REGISTER_XLA_OP(Name("StatelessIf").AllowResourceTypes(), XlaIfOp);
REGISTER_XLA_OP(Name("XlaIf").AllowResourceTypes(), XlaIfOp);

}  // namespace tensorflow
<commit_msg>Remove code that is no longer valid post change away from lowering to while loops.<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/tf2xla/kernels/if_op.h"

#include "tensorflow/compiler/tf2xla/shape_util.h"
#include "tensorflow/compiler/tf2xla/xla_context.h"
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"

namespace tensorflow {

XlaIfOp::XlaIfOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) {
  const NameAttrList* name_attr;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("then_branch", &name_attr));
  then_branch_ = *name_attr;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("else_branch", &name_attr));
  else_branch_ = *name_attr;

  OP_REQUIRES_OK(ctx, ctx->GetAttr("Tcond", &cond_type_));
  OP_REQUIRES_OK(ctx, ctx->GetAttr("Tin", &input_types_));
  OP_REQUIRES_OK(ctx, ctx->GetAttr("Tout", &output_types_));
}

// TODO(b/35949885): There is duplication here with the handling of the
// while_op. Refactor the common code out/rework.
void XlaIfOp::Compile(XlaOpKernelContext* ctx) {
  xla::XlaBuilder* b = ctx->builder();

  OP_REQUIRES(ctx, cond_type_ == DT_BOOL,
              errors::InvalidArgument(
                  "Condition argument must be a boolean for XLA compilation"));
  OP_REQUIRES(ctx, TensorShapeUtils::IsScalar(ctx->InputShape(0)),
              errors::InvalidArgument(
                  "Condition argument must be a scalar for XLA compilation"));

  VLOG(1) << "Building If: " << input_types_.size() << " inputs";

  std::vector<XlaCompiler::Argument> arguments(input_types_.size());
  for (int i = 0; i < input_types_.size(); ++i) {
    XlaCompiler::Argument& arg = arguments[i];
    DataType type = ctx->input_type(i + 1);

    if (type == DT_RESOURCE) {
      XlaResource* resource;
      OP_REQUIRES_OK(ctx, ctx->GetResourceInput(i + 1, &resource));

      arg.initialized = resource->initialized();
      arg.kind = XlaCompiler::Argument::kResource;
      arg.resource_kind = resource->kind();

      arg.type = resource->type();
      arg.shape = resource->shape();
      OP_REQUIRES(ctx, arg.initialized,
                  errors::Unimplemented("Uninitialized arguments: ", arg.name));
      arg.tensor_array_size = resource->tensor_array_size();
      for (const auto& gradient : resource->tensor_array_gradients()) {
        arg.tensor_array_gradients.insert(gradient.first);
      }
      arg.name = resource->name();
      VLOG(2) << "Resource " << resource->name()
              << " type: " << DataTypeString(arg.type)
              << " shape: " << arg.shape.DebugString()
              << " initialized: " << arg.initialized;
    } else {
      arg.kind = XlaCompiler::Argument::kParameter;
      arg.type = input_types_[i];
      arg.shape = ctx->InputShape(i + 1);
      VLOG(2) << "Arg type: " << DataTypeString(arg.type)
              << " shape: " << arg.shape.DebugString();
    }
  }

  // Compile both branches of the conditional.
  XlaCompiler::CompileOptions options;
  options.use_tuple_arg = true;
  options.resolve_compile_time_constants = false;
  options.return_updated_values_for_all_resources = true;
  options.is_entry_computation = false;
  XlaCompiler* compiler = ctx->compiler();

  XlaCompiler::CompilationResult then_result;
  OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, then_branch_,
                                                arguments, &then_result));
  XlaCompiler::CompilationResult else_result;
  OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, else_branch_,
                                                arguments, &else_result));

  bool has_tensor_array_gradients = false;
  for (XlaCompiler::CompilationResult* result : {&then_result, &else_result}) {
    for (const XlaCompiler::ResourceUpdate& update : result->resource_updates) {
      XlaResource* resource;
      OP_REQUIRES_OK(ctx,
                     ctx->GetResourceInput(update.input_index + 1, &resource));
      XlaCompiler::Argument& arg = arguments[update.input_index];

      // Add any TensorArray gradients touched by the then/else computation to
      // the enclosing graph.
      for (const string& grad_source : update.tensor_array_gradients_accessed) {
        VLOG(5) << "TensorArray " << resource->name() << " accessed gradient "
                << grad_source;
        XlaResource* gradient;
        OP_REQUIRES_OK(ctx, resource->GetOrCreateTensorArrayGradient(
                                grad_source, b, &gradient));
      }
      // Add all of the TensorArray gradients to the argument. For simplicity,
      // we always pass all known gradients.
      for (const auto& gradient : resource->tensor_array_gradients()) {
        arg.tensor_array_gradients.insert(gradient.first);
      }
      if (!resource->tensor_array_gradients().empty())
        has_tensor_array_gradients = true;
    }
  }

  // Recompile the functions to update the argument shapes for tensor arrays.
  if (has_tensor_array_gradients) {
    then_result = {};
    OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, then_branch_,
                                                  arguments, &then_result));
    else_result = {};
    OP_REQUIRES_OK(ctx, compiler->CompileFunction(options, else_branch_,
                                                  arguments, &else_result));
  }

  // Check that both branches have identical input shapes.
  OP_REQUIRES(ctx, then_result.xla_input_shapes.size() == 1,
              errors::FailedPrecondition("Expected one input shape"));
  xla::Shape then_input_shape = then_result.xla_input_shapes[0];
  OP_REQUIRES(ctx, xla::ShapeUtil::IsTuple(then_input_shape),
              errors::FailedPrecondition("Expected tuple shape"));
  OP_REQUIRES(ctx, else_result.xla_input_shapes.size() == 1,
              errors::FailedPrecondition("Expected one input shape"));
  xla::Shape else_input_shape = else_result.xla_input_shapes[0];
  OP_REQUIRES(ctx, xla::ShapeUtil::IsTuple(else_input_shape),
              errors::FailedPrecondition("Expected tuple shape"));
  OP_REQUIRES(ctx,
              xla::ShapeUtil::Compatible(then_input_shape, else_input_shape),
              errors::InvalidArgument(
                  "Input shapes of then and else branches do not match: ",
                  xla::ShapeUtil::HumanString(then_input_shape), " vs. ",
                  xla::ShapeUtil::HumanString(else_input_shape)));

  // Check that both branches have identical output shapes.
  OP_REQUIRES(
      ctx,
      xla::ShapeUtil::Compatible(then_result.xla_output_shape,
                                 else_result.xla_output_shape),
      errors::InvalidArgument(
          "Output shapes of then and else branches do not match: ",
          xla::ShapeUtil::HumanString(then_result.xla_output_shape), " vs. ",
          xla::ShapeUtil::HumanString(else_result.xla_output_shape)));

  VLOG(2) << "Input shape: " << xla::ShapeUtil::HumanString(then_input_shape);
  VLOG(2) << "Output shape: "
          << xla::ShapeUtil::HumanString(then_result.xla_output_shape);

  // We set return_updated_values_for_all_resources=true and we pass the same
  // arguments to both computations, so the resource update count must match.
  OP_REQUIRES(ctx,
              then_result.resource_updates.size() ==
                  else_result.resource_updates.size(),
              errors::FailedPrecondition(
                  "Different number of resources in then and else branch"));
  for (int i = 0; i < then_result.resource_updates.size(); ++i) {
    const auto& lhs = then_result.resource_updates[i];
    const auto& rhs = else_result.resource_updates[i];
    bool equal = lhs.input_index == rhs.input_index && lhs.shape == rhs.shape &&
                 lhs.tensor_array_gradients_accessed ==
                     rhs.tensor_array_gradients_accessed;
    OP_REQUIRES(
        ctx, equal,
        errors::FailedPrecondition(
            "Mismatch in resource of then and else branch for resource ", i));
  }

  int num_inputs = then_result.input_mapping.size();
  std::vector<xla::XlaOp> inputs(num_inputs);
  for (int i = 0; i < num_inputs; ++i) {
    int input_num = then_result.input_mapping[i] + 1;
    if (ctx->input_type(input_num) == DT_RESOURCE) {
      XlaResource* resource;
      OP_REQUIRES_OK(ctx, ctx->GetResourceInput(input_num, &resource));
      OP_REQUIRES_OK(ctx, resource->Pack(&inputs[i], b));
    } else {
      inputs[i] = ctx->Input(i + 1);
    }
  }

  bool resource_variable_seen = false;
  for (int i = 0; i < ctx->num_inputs(); ++i) {
    if (ctx->input_type(i) == DT_RESOURCE) {
      resource_variable_seen = true;
    } else {
      OP_REQUIRES(
          ctx, !resource_variable_seen,
          errors::FailedPrecondition(
              "Resource variables and regular inputs cannot be interleaved."));
    }
  }

  xla::XlaOp outputs = xla::Conditional(
      ctx->Input(0), xla::Tuple(b, inputs), *then_result.computation,
      xla::Tuple(b, inputs), *else_result.computation);
  // Sets non-variable outputs.
  for (int i = 0; i < output_types_.size(); ++i) {
    xla::XlaOp output_handle = xla::GetTupleElement(outputs, i);
    if (VLOG_IS_ON(2)) {
      LOG(INFO) << "Setting output " << i;
      auto shape_or = b->GetShape(output_handle);
      if (shape_or.ok()) {
        LOG(INFO) << "Shape for output " << i << ": "
                  << xla::ShapeUtil::HumanString(shape_or.ValueOrDie());
      } else {
        LOG(INFO) << "Shape unknown for output " << i;
      }
    }
    ctx->SetOutput(i, output_handle);
  }

  // Updates the values of any resource variables modified by the conditional
  // bodies.
  for (XlaCompiler::CompilationResult* result : {&then_result, &else_result}) {
    for (int i = 0; i < result->resource_updates.size(); ++i) {
      const XlaCompiler::ResourceUpdate& update = result->resource_updates[i];
      XlaResource* resource;
      OP_REQUIRES_OK(ctx,
                     ctx->GetResourceInput(update.input_index + 1, &resource));
      if (update.modified) {
        int pos = result->outputs.size() + i;
        OP_REQUIRES_OK(ctx,
                       resource->SetFromPack(
                           arguments[update.input_index].tensor_array_gradients,
                           xla::GetTupleElement(outputs, pos), b));
      }
      VLOG(2) << "If variable: pos: " << update.input_index
              << " name: " << resource->name()
              << " modified: " << update.modified
              << " type: " << DataTypeString(update.type)
              << " shape: " << update.shape.DebugString();
    }
  }
  VLOG(1) << "Done building If";
}

REGISTER_XLA_OP(Name("If").AllowResourceTypes(), XlaIfOp);
REGISTER_XLA_OP(Name("StatelessIf").AllowResourceTypes(), XlaIfOp);
REGISTER_XLA_OP(Name("XlaIf").AllowResourceTypes(), XlaIfOp);

}  // namespace tensorflow
<|endoftext|>


<commit_before>#ifndef ALEPH_TOPOLOGY_IO_MATRIX_HH__
#define ALEPH_TOPOLOGY_IO_MATRIX_HH__

#include <aleph/utilities/String.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <algorithm>
#include <fstream>
#include <istream>
#include <string>
#include <unordered_map>
#include <vector>

#include <cmath>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class BipartiteAdjacencyMatrixReader
  @brief Reads bipartite adjacency matrices in text format

  This reader class is meant to load bipartite adjacency matrices in
  text format. Every row of the matrix represents edges that connect
  nodes from the first class with nodes of the second class. Weights
  that are non-zero are used to indicate the presence of an edge.

  The number of rows and columns must not vary over the file. An *empty*
  line is permitted, though. Likewise, lines starting with `#` will just
  be ignored. An example of a 2-by-3 matrix follows:

  \code
  0 1 2
  3 4 5
  \endcode

  All simplicial complexes created by this class will be reported
  in filtration order, following the detected weights.
*/

class BipartiteAdjacencyMatrixReader
{
public:

  /**
    Reads a simplicial complex from a file.

    @param filename Input filename
    @param  K       Simplicial complex
  */

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( in, K );
  }

  /** @overload operator()( const std::string&, SimplicialComplex& ) */
  template <class SimplicialComplex> void operator()( std::istream& in, SimplicialComplex& K )
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    auto position      = in.tellg();
    std::size_t height = 0;

    // An 'unrolled' version of all edge weights that can be read from
    // the file. They are supposed to correspond to a matrix with some
    // number of columns and some number of rows.
    std::vector<DataType> values;

    using namespace aleph::utilities;

    {
      std::string line;
      while( std::getline( in, line ) )
        ++height;

      in.clear();
      in.seekg( position );
    }

    std::copy( std::istream_iterator<DataType>( in ), std::istream_iterator<DataType>(),
               std::back_inserter( values ) );

    // We cannot fill an empty simplicial complex. It might be useful to
    // throw an error here, though.
    if( values.empty() )
      return;

    _height = height;
    _width  = values.size() / height;
    if( values.size() % height != 0 )
      throw std::runtime_error( "Format error: number of columns must not vary" );

    // This is required in order to assign the weight of nodes
    // correctly; we cannot trust the weights to be positive.
    auto minData = *std::min_element( values.begin(), values.end() );

    std::vector<Simplex> simplices;
    simplices.reserve( _width * _height + ( _width + _height ) );

    // Edges -----------------------------------------------------------
    //
    // Create the edges first and update information about their weights
    // along with them.

    // For determining the minimum weight, we first loop over all
    // possible edges, create a lookup table for the weights, and
    // finally create all the vertices using this lookup table. A
    // vertex will only information stored here if the right flag
    // has been set by the client.
    std::unordered_map<VertexType, DataType> minWeight;

    auto updateOrSetWeight
      = [&minWeight] ( const VertexType& v, const DataType& w )
        {
          if( minWeight.find( v ) == minWeight.end() )
            minWeight[v] = w;
          else
            minWeight[v] = std::min( minWeight[v], w );
        };

    for( std::size_t y = 0; y < _height; y++ )
    {
      for( std::size_t x = 0; x < _width; x++ )
      {
        auto i = static_cast<VertexType>( _width * y + x   );
        auto w = values[i];

        // Map matrix indices to the corresponding vertex indices as
        // outline above.
        auto u = VertexType(y);
        auto v = VertexType(x + _height);

        updateOrSetWeight( u, w );
        updateOrSetWeight( v, w );

        simplices.push_back( Simplex( {u,v}, w ) );
      }
    }

    // Vertices --------------------------------------------------------
    //
    // Create a vertex for every node in the input data. An (n,m)-matrix
    // thus gives rise to n+m nodes.

    for( std::size_t i = 0; i < _height + _width; i++ )
    {
      simplices.push_back(
        Simplex( VertexType( i ),
          _assignMinimumVertexWeight
            ?  minWeight[ VertexType(i) ]
            :  minData )
      );
    }

    K = SimplicialComplex( simplices.begin(), simplices.end() );

    // Establish filtration order based on weights. There does not seem
    // to be much of a point to make this configurable; the edge weight
    // is a given property of the data.
    K.sort(
      filtrations::Data<Simplex>()
    );
  }

  /** @returns Height of matrix that was read last */
  std::size_t height() const noexcept { return _height; }

  /** @returns Width of matrix that was read last */
  std::size_t width()  const noexcept { return _width;  }

  /** Permits changing the behaviour of vertex weight assignment */
  void setAssignMinimumVertexWeight( bool value = true )
  {
    _assignMinimumVertexWeight = value;
  }

  /** @returns Flag whether vertex weights are assigned to be minimal or not */
  bool assignMinimumVertexWeight() const noexcept
  {
    return _assignMinimumVertexWeight;
  }

private:
  std::size_t _height = 0;
  std::size_t _width  = 0;

  /**
    If set, assigns the minimum vertex weight according to the minimum
    edge weight that is connected to the given vertex. Else, *all* the
    vertices will get a weight of zero.
  */

  bool _assignMinimumVertexWeight = false;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Added support for absolute values<commit_after>#ifndef ALEPH_TOPOLOGY_IO_MATRIX_HH__
#define ALEPH_TOPOLOGY_IO_MATRIX_HH__

#include <aleph/utilities/String.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <algorithm>
#include <fstream>
#include <istream>
#include <string>
#include <unordered_map>
#include <vector>

#include <cmath>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class BipartiteAdjacencyMatrixReader
  @brief Reads bipartite adjacency matrices in text format

  This reader class is meant to load bipartite adjacency matrices in
  text format. Every row of the matrix represents edges that connect
  nodes from the first class with nodes of the second class. Weights
  that are non-zero are used to indicate the presence of an edge.

  The number of rows and columns must not vary over the file. An *empty*
  line is permitted, though. Likewise, lines starting with `#` will just
  be ignored. An example of a 2-by-3 matrix follows:

  \code
  0 1 2
  3 4 5
  \endcode

  All simplicial complexes created by this class will be reported
  in filtration order, following the detected weights.
*/

class BipartiteAdjacencyMatrixReader
{
public:

  /**
    Reads a simplicial complex from a file.

    @param filename Input filename
    @param  K       Simplicial complex
  */

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( in, K );
  }

  /** @overload operator()( const std::string&, SimplicialComplex& ) */
  template <class SimplicialComplex> void operator()( std::istream& in, SimplicialComplex& K )
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    auto position      = in.tellg();
    std::size_t height = 0;

    // An 'unrolled' version of all edge weights that can be read from
    // the file. They are supposed to correspond to a matrix with some
    // number of columns and some number of rows.
    std::vector<DataType> values;

    using namespace aleph::utilities;

    {
      std::string line;
      while( std::getline( in, line ) )
        ++height;

      in.clear();
      in.seekg( position );
    }

    std::copy( std::istream_iterator<DataType>( in ), std::istream_iterator<DataType>(),
               std::back_inserter( values ) );

    // We cannot fill an empty simplicial complex. It might be useful to
    // throw an error here, though.
    if( values.empty() )
      return;

    _height = height;
    _width  = values.size() / height;
    if( values.size() % height != 0 )
      throw std::runtime_error( "Format error: number of columns must not vary" );

    // This is required in order to assign the weight of nodes
    // correctly; we cannot trust the weights to be positive.
    auto minData = *std::min_element( values.begin(), values.end() );

    std::vector<Simplex> simplices;
    simplices.reserve( _width * _height + ( _width + _height ) );

    // Edges -----------------------------------------------------------
    //
    // Create the edges first and update information about their weights
    // along with them.

    // For determining the minimum weight, we first loop over all
    // possible edges, create a lookup table for the weights, and
    // finally create all the vertices using this lookup table. A
    // vertex will only information stored here if the right flag
    // has been set by the client.
    std::unordered_map<VertexType, DataType> minWeight;

    auto updateOrSetWeight
      = [&minWeight, this] ( const VertexType& v, const DataType& w )
        {
          if( minWeight.find( v ) == minWeight.end() )
            minWeight[v] = w;
          else
          {
            if( _assignMinimumAbsoluteVertexWeight )
            {
              if( std::abs( w ) < minWeight[v] )
                minWeight[v] = w;
            }
            else
              minWeight[v] = std::min( minWeight[v], w );
          }
        };

    for( std::size_t y = 0; y < _height; y++ )
    {
      for( std::size_t x = 0; x < _width; x++ )
      {
        auto i = static_cast<VertexType>( _width * y + x   );
        auto w = values[i];

        // Map matrix indices to the corresponding vertex indices as
        // outline above.
        auto u = VertexType(y);
        auto v = VertexType(x + _height);

        updateOrSetWeight( u, w );
        updateOrSetWeight( v, w );

        simplices.push_back( Simplex( {u,v}, w ) );
      }
    }

    // Vertices --------------------------------------------------------
    //
    // Create a vertex for every node in the input data. An (n,m)-matrix
    // thus gives rise to n+m nodes.

    for( std::size_t i = 0; i < _height + _width; i++ )
    {
      // Notice that that `minWeight` map is guaranteed to contain the
      // weight (potentially signed) that corresponds to the vertex. A
      // different way of setting up the map depends on the flags that
      // are set by the client.
      simplices.push_back(
        Simplex( VertexType( i ),
          _assignMinimumVertexWeight || _assignMinimumAbsoluteVertexWeight
            ?  minWeight[ VertexType(i) ]
            :  minData )
      );
    }

    K = SimplicialComplex( simplices.begin(), simplices.end() );

    // Establish filtration order based on weights. There does not seem
    // to be much of a point to make this configurable; the edge weight
    // is a given property of the data.
    K.sort(
      filtrations::Data<Simplex>()
    );
  }

  /** @returns Height of matrix that was read last */
  std::size_t height() const noexcept { return _height; }

  /** @returns Width of matrix that was read last */
  std::size_t width()  const noexcept { return _width;  }

  /** Permits changing the behaviour of vertex weight assignment */
  void setAssignMinimumAbsoluteVertexWeight( bool value = true )
  {
    _assignMinimumAbsoluteVertexWeight = value;
  }

  /** @returns Flag whether vertex weights are assigned to be minimal or not */
  bool assignMinimumAbsoluteVertexWeight() const noexcept
  {
    return _assignMinimumAbsoluteVertexWeight;
  }

  /** Permits changing the behaviour of vertex weight assignment */
  void setAssignMinimumVertexWeight( bool value = true )
  {
    _assignMinimumVertexWeight = value;
  }

  /** @returns Flag whether vertex weights are assigned to be minimal or not */
  bool assignMinimumVertexWeight() const noexcept
  {
    return _assignMinimumVertexWeight;
  }

private:
  std::size_t _height = 0;
  std::size_t _width  = 0;

  /**
    If set, assigns the minimum vertex weight according to the minimum
    absolute edge weight that is connected to the given vertex. All of
    the vertices will get a weight of zero otherwise.
  */

  bool _assignMinimumAbsoluteVertexWeight = false;

  /**
    If set, assigns the minimum vertex weight according to the minimum
    edge weight that is connected to the given vertex. Else, *all* the
    vertices will get a weight of zero.
  */

  bool _assignMinimumVertexWeight = false;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2016 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_UNICODE_STRING_GRAMMAR_X3_DEF_HPP
#define MAPNIK_JSON_UNICODE_STRING_GRAMMAR_X3_DEF_HPP

#include <mapnik/json/unicode_string_grammar_x3.hpp>
#include <iostream>

namespace mapnik { namespace json { namespace grammar {

namespace x3 = boost::spirit::x3;

using uchar = std::uint32_t; // a unicode code point

auto append = [](auto const& ctx)
{
    _val(ctx) += _attr(ctx);
};

namespace detail {

void push_utf8_impl(std::string & str, uchar code_point)
{
    using insert_iterator = std::back_insert_iterator<std::string>;
    insert_iterator iter(str);
    boost::utf8_output_iterator<insert_iterator> utf8_iter(iter);
    *utf8_iter++ = code_point;
}
}

auto push_char = [](auto const& ctx) { _val(ctx).push_back(_attr(ctx));};

auto push_utf8 = [](auto const& ctx) { detail::push_utf8_impl(_val(ctx), _attr(ctx));};

auto push_esc = [] (auto const& ctx)
{
    std::string & utf8 = _val(ctx);
    char c = _attr(ctx);
    switch (c)
    {
    case ' ': utf8 += ' ';          break;
    case '\t': utf8 += '\t';        break;
    case '0': utf8 += char(0);      break;
    case 'a': utf8 += 0x7;          break;
    case 'b': utf8 += 0x8;          break;
    case 't': utf8 += 0x9;          break;
    case 'n': utf8 += 0xA;          break;
    case 'v': utf8 += 0xB;          break;
    case 'f': utf8 += 0xC;          break;
    case 'r': utf8 += 0xD;          break;
    case 'e': utf8 += 0x1B;         break;
    case '"': utf8 += '"';          break;
    case '/': utf8 += '/';          break;
    case '\\': utf8 += '\\';        break;
    case '_': detail::push_utf8_impl(utf8, 0xA0);  break;
    case 'N': detail::push_utf8_impl(utf8, 0x85);  break;
    case 'L': detail::push_utf8_impl(utf8, 0x2028);  break;
    case 'P': detail::push_utf8_impl(utf8, 0x2029);  break;
    }
};

using x3::lit;
using x3::char_;
using x3::eol;
using x3::no_skip;

x3::uint_parser<char,  16, 2, 2> const hex2 {};
x3::uint_parser<uchar, 16, 4, 4> const hex4 {};
x3::uint_parser<uchar, 16, 8, 8> const hex8 {};

// start rule
unicode_string_grammar_type const unicode_string("Unicode String");
// rules
x3::rule<class double_quoted_tag, std::string> const double_quoted("Double-quoted string");
x3::rule<class escaped_tag, std::string> const escaped("Escaped Characted");

auto unicode_string_def = double_quoted
    ;
auto const escaped_def = lit('\\') >
    ((lit('x') > hex2[push_char])
     |
     (lit('u') > hex4[push_utf8])
     |
     (lit('U') > hex8[push_utf8])
     |
     char_("0abtnvfre\"/\\N_LP \t")[push_esc]
     |
     eol) // continue to next line
    ;

auto const double_quoted_def = lit('"') > no_skip[*(escaped[append] | (~char_('"'))[append])] > lit('"');

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>

BOOST_SPIRIT_DEFINE(
    unicode_string,
    double_quoted,
    escaped
    );

#pragma GCC diagnostic pop

}
grammar::unicode_string_grammar_type const& unicode_string_grammar()
{
    return grammar::unicode_string;
}
}}

#endif // MAPNIK_JSON_UNICODE_STRING_GRAMMAR_X3_DEF_HPP
<commit_msg>relax hex4 parser to allow 5 character \unnnnn code points<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2016 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_UNICODE_STRING_GRAMMAR_X3_DEF_HPP
#define MAPNIK_JSON_UNICODE_STRING_GRAMMAR_X3_DEF_HPP

#include <mapnik/json/unicode_string_grammar_x3.hpp>
#include <iostream>

namespace mapnik { namespace json { namespace grammar {

namespace x3 = boost::spirit::x3;

using uchar = std::uint32_t; // a unicode code point

auto append = [](auto const& ctx)
{
    _val(ctx) += _attr(ctx);
};

namespace detail {

void push_utf8_impl(std::string & str, uchar code_point)
{
    using insert_iterator = std::back_insert_iterator<std::string>;
    insert_iterator iter(str);
    boost::utf8_output_iterator<insert_iterator> utf8_iter(iter);
    *utf8_iter++ = code_point;
}
}

auto push_char = [](auto const& ctx) { _val(ctx).push_back(_attr(ctx));};

auto push_utf8 = [](auto const& ctx) { detail::push_utf8_impl(_val(ctx), _attr(ctx));};

auto push_esc = [] (auto const& ctx)
{
    std::string & utf8 = _val(ctx);
    char c = _attr(ctx);
    switch (c)
    {
    case ' ': utf8 += ' ';          break;
    case '\t': utf8 += '\t';        break;
    case '0': utf8 += char(0);      break;
    case 'a': utf8 += 0x7;          break;
    case 'b': utf8 += 0x8;          break;
    case 't': utf8 += 0x9;          break;
    case 'n': utf8 += 0xA;          break;
    case 'v': utf8 += 0xB;          break;
    case 'f': utf8 += 0xC;          break;
    case 'r': utf8 += 0xD;          break;
    case 'e': utf8 += 0x1B;         break;
    case '"': utf8 += '"';          break;
    case '/': utf8 += '/';          break;
    case '\\': utf8 += '\\';        break;
    case '_': detail::push_utf8_impl(utf8, 0xA0);  break;
    case 'N': detail::push_utf8_impl(utf8, 0x85);  break;
    case 'L': detail::push_utf8_impl(utf8, 0x2028);  break;
    case 'P': detail::push_utf8_impl(utf8, 0x2029);  break;
    }
};

using x3::lit;
using x3::char_;
using x3::eol;
using x3::no_skip;

x3::uint_parser<char,  16, 2, 2> const hex2 {};
x3::uint_parser<uchar, 16, 4, 5> const hex4 {};
x3::uint_parser<uchar, 16, 8, 8> const hex8 {};

// start rule
unicode_string_grammar_type const unicode_string("Unicode String");
// rules
x3::rule<class double_quoted_tag, std::string> const double_quoted("Double-quoted string");
x3::rule<class escaped_tag, std::string> const escaped("Escaped Characted");

auto unicode_string_def = double_quoted
    ;
auto const escaped_def = lit('\\') >
    ((lit('x') > hex2[push_char])
     |
     (lit('u') > hex4[push_utf8])
     |
     (lit('U') > hex8[push_utf8])
     |
     char_("0abtnvfre\"/\\N_LP \t")[push_esc]
     |
     eol) // continue to next line
    ;

auto const double_quoted_def = lit('"') > no_skip[*(escaped[append] | (~char_('"'))[append])] > lit('"');

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>

BOOST_SPIRIT_DEFINE(
    unicode_string,
    double_quoted,
    escaped
    );

#pragma GCC diagnostic pop

}
grammar::unicode_string_grammar_type const& unicode_string_grammar()
{
    return grammar::unicode_string;
}
}}

#endif // MAPNIK_JSON_UNICODE_STRING_GRAMMAR_X3_DEF_HPP
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/UserInterface/UserInterface.h"

#include "cling/Interpreter/StoredValueRef.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "textinput/TextInput.h"
#include "textinput/StreamReader.h"
#include "textinput/TerminalDisplay.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/PathV1.h"
#include "llvm/Config/config.h"

// Fragment copied from LLVM's raw_ostream.cpp
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif

#if defined(_MSC_VER)
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#endif

namespace cling {
  UserInterface::UserInterface(Interpreter& interp) {
    // We need stream that doesn't close its file descriptor, thus we are not
    // using llvm::outs. Keeping file descriptor open we will be able to use
    // the results in pipes (Savannah #99234).
    static llvm::raw_fd_ostream m_MPOuts (STDOUT_FILENO, /*ShouldClose*/false);
    m_MetaProcessor.reset(new MetaProcessor(interp, m_MPOuts));
  }

  UserInterface::~UserInterface() {}

  void UserInterface::runInteractively(bool nologo /* = false */) {
    if (!nologo) {
      PrintLogo();
    }

    // History file is $HOME/.cling_history
    static const char* histfile = ".cling_history";
    llvm::sys::Path histfilePath = llvm::sys::Path::GetUserHomeDirectory();
    histfilePath.appendComponent(histfile);

    using namespace textinput;
    StreamReader* R = StreamReader::Create();
    TerminalDisplay* D = TerminalDisplay::Create();
    TextInput TI(*R, *D, histfilePath.c_str());

    TI.SetPrompt("[cling]$ ");
    std::string line;
    try {
      while (true) {
        m_MetaProcessor->getOuts().flush();
        TextInput::EReadResult RR = TI.ReadInput();
        TI.TakeInput(line);
        if (RR == TextInput::kRREOF) {
          break;
        }

        cling::Interpreter::CompilationResult compRes;
        int indent
          = m_MetaProcessor->process(line.c_str(), compRes, 0/*result*/);
        // Quit requested
        if (indent < 0)
          break;
        std::string Prompt = "[cling]";
        if (m_MetaProcessor->getInterpreter().isRawInputEnabled())
          Prompt.append("! ");
        else
          Prompt.append("$ ");

        if (indent > 0)
          // Continuation requested.
          Prompt.append('?' + std::string(indent * 3, ' '));

        TI.SetPrompt(Prompt.c_str());

      }
    }
    catch() {
      llvm::errs() << "Exception occurred. Recovering...\n";
    }
  }

  void UserInterface::PrintLogo() {
    llvm::raw_ostream& outs = m_MetaProcessor->getOuts();
    outs << "\n";
    outs << "****************** CLING ******************" << "\n";
    outs << "* Type C++ code and press enter to run it *" << "\n";
    outs << "*             Type .q to exit             *" << "\n";
    outs << "*******************************************" << "\n";
  }
} // end namespace cling
<commit_msg>The standard said use catch(...) and not catch()<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/UserInterface/UserInterface.h"

#include "cling/Interpreter/StoredValueRef.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "textinput/TextInput.h"
#include "textinput/StreamReader.h"
#include "textinput/TerminalDisplay.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/PathV1.h"
#include "llvm/Config/config.h"

// Fragment copied from LLVM's raw_ostream.cpp
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif

#if defined(_MSC_VER)
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#endif

namespace cling {
  UserInterface::UserInterface(Interpreter& interp) {
    // We need stream that doesn't close its file descriptor, thus we are not
    // using llvm::outs. Keeping file descriptor open we will be able to use
    // the results in pipes (Savannah #99234).
    static llvm::raw_fd_ostream m_MPOuts (STDOUT_FILENO, /*ShouldClose*/false);
    m_MetaProcessor.reset(new MetaProcessor(interp, m_MPOuts));
  }

  UserInterface::~UserInterface() {}

  void UserInterface::runInteractively(bool nologo /* = false */) {
    if (!nologo) {
      PrintLogo();
    }

    // History file is $HOME/.cling_history
    static const char* histfile = ".cling_history";
    llvm::sys::Path histfilePath = llvm::sys::Path::GetUserHomeDirectory();
    histfilePath.appendComponent(histfile);

    using namespace textinput;
    StreamReader* R = StreamReader::Create();
    TerminalDisplay* D = TerminalDisplay::Create();
    TextInput TI(*R, *D, histfilePath.c_str());

    TI.SetPrompt("[cling]$ ");
    std::string line;
    try {
      while (true) {
        m_MetaProcessor->getOuts().flush();
        TextInput::EReadResult RR = TI.ReadInput();
        TI.TakeInput(line);
        if (RR == TextInput::kRREOF) {
          break;
        }

        cling::Interpreter::CompilationResult compRes;
        int indent
          = m_MetaProcessor->process(line.c_str(), compRes, 0/*result*/);
        // Quit requested
        if (indent < 0)
          break;
        std::string Prompt = "[cling]";
        if (m_MetaProcessor->getInterpreter().isRawInputEnabled())
          Prompt.append("! ");
        else
          Prompt.append("$ ");

        if (indent > 0)
          // Continuation requested.
          Prompt.append('?' + std::string(indent * 3, ' '));

        TI.SetPrompt(Prompt.c_str());

      }
    }
    catch(...) {
      llvm::errs() << "Exception occurred. Recovering...\n";
    }
  }

  void UserInterface::PrintLogo() {
    llvm::raw_ostream& outs = m_MetaProcessor->getOuts();
    outs << "\n";
    outs << "****************** CLING ******************" << "\n";
    outs << "* Type C++ code and press enter to run it *" << "\n";
    outs << "*             Type .q to exit             *" << "\n";
    outs << "*******************************************" << "\n";
  }
} // end namespace cling
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// updater.cpp
//
// Identification: src/codegen/updater.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "codegen/updater.h"
#include "codegen/transaction_runtime.h"
#include "common/container_tuple.h"
#include "concurrency/transaction_manager_factory.h"
#include "executor/executor_context.h"
#include "storage/data_table.h"
#include "storage/tile_group_header.h"
#include "storage/tile_group.h"
#include "storage/tile.h"
#include "storage/tuple.h"
#include "type/abstract_pool.h"
#include "type/types.h"
#include "type/value.h"

namespace peloton {
namespace codegen {

void Updater::Init(storage::DataTable *table,
                   executor::ExecutorContext *executor_context,
                   Target *target_vector, uint32_t target_vector_size) {
  PL_ASSERT(table != nullptr && executor_context != nullptr&&
            target_vector != nullptr);
  table_ = table;
  executor_context_ = executor_context;
  // Target list is kept since it is required at a new version update
  target_list_ =
      new TargetList(target_vector, target_vector + target_vector_size);
}

char *Updater::GetDataPtr(uint32_t tile_group_id, uint32_t tuple_offset) {
  auto tile_group = table_->GetTileGroupById(tile_group_id);

  // Get the tile offset assuming that it is still in a tuple format
  oid_t tile_offset, tile_column_offset;
  tile_group->LocateTileAndColumn(0, tile_offset, tile_column_offset);
  tile_ = tile_group->GetTileReference(tile_offset);
  return tile_->GetTupleLocation(tuple_offset);
}

char *Updater::Prepare(uint32_t tile_group_id, uint32_t tuple_offset) {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(tile_group_id).get();
  auto *tile_group_header = tile_group->GetHeader();
  old_location_.block = tile_group_id;
  old_location_.offset = tuple_offset;

  // If I am the owner, update in-place
  is_owner_ = TransactionRuntime::IsOwner(*txn, tile_group_header,
                                          tuple_offset);
  if (is_owner_ == true)
    return GetDataPtr(tile_group_id, tuple_offset);

  // If not the owner, acquire ownership and build a new version tuple
  acquired_ownership_ = TransactionRuntime::AcquireOwnership(*txn,
      tile_group_header, tuple_offset);
  if (acquired_ownership_ == false)
    return nullptr;

  new_location_ = table_->AcquireVersion();
  return GetDataPtr(new_location_.block, new_location_.offset);
}

char *Updater::PreparePK(uint32_t tile_group_id, uint32_t tuple_offset) {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(tile_group_id).get();
  auto *tile_group_header = tile_group->GetHeader();

  // Check ownership
  is_owner_ = TransactionRuntime::IsOwner(*txn, tile_group_header,
                                          tuple_offset);
  acquired_ownership_ = false;
  if (is_owner_ == false) {
    acquired_ownership_ = TransactionRuntime::AcquireOwnership(
        *txn, tile_group_header, tuple_offset);
    if (acquired_ownership_ == false)
      return nullptr;
  }

  // Delete the old tuple
  ItemPointer old_location(tile_group_id, tuple_offset);
  ItemPointer empty_location = table_->InsertEmptyVersion();
  if (empty_location.IsNull() == true && acquired_ownership_ == true) {
    TransactionRuntime::YieldOwnership(*txn, tile_group_header,
                                       tuple_offset);
    return nullptr;
  }
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  txn_manager.PerformDelete(txn, old_location, empty_location);

  // Get the tuple data pointer for a new version
  new_location_ = table_->GetEmptyTupleSlot(nullptr);
  return GetDataPtr(new_location_.block, new_location_.offset);
}

peloton::type::AbstractPool *Updater::GetPool() {
  // This should be called after Prepare() or PreparePK()
  PL_ASSERT(tile_);
  return tile_->GetPool();
}

void Updater::Update() {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  LOG_TRACE("Updating tuple <%u, %u> from table '%s' (db ID: %u, table ID: %u)",
            old_location_.block, old_location_.offset,
            table_->GetName().c_str(), table_->GetDatabaseOid(),
            table_->GetOid());
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(old_location_.block).get();
  auto *tile_group_header = tile_group->GetHeader();
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();

  // Either update in-place
  if (is_owner_ == true) {
    txn_manager.PerformUpdate(txn, old_location_);
    executor_context_->num_processed++;
    return;
  }

  // Or, update with a new version
  ContainerTuple<storage::TileGroup> new_tuple(
    table_->GetTileGroupById(new_location_.block).get(), new_location_.offset);
  ItemPointer *indirection =
      tile_group_header->GetIndirection(old_location_.offset);
  auto result = table_->InstallVersion(&new_tuple, target_list_, txn,
                                       indirection);
  if (result == false) {
    TransactionRuntime::YieldOwnership(*txn, tile_group_header,
                                       old_location_.offset);
    return;
  }
  txn_manager.PerformUpdate(txn, old_location_, new_location_);
  executor_context_->num_processed++;
}

void Updater::UpdatePK() {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  LOG_TRACE("Updating tuple <%u, %u> from table '%s' (db ID: %u, table ID: %u)",
            old_location_.block, old_location_.offset,
            table_->GetName().c_str(), table_->GetDatabaseOid(),
            table_->GetOid());
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(new_location_.block).get();
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();

  // Insert a new tuple
  ContainerTuple<storage::TileGroup> tuple(tile_group, new_location_.offset);
  ItemPointer *index_entry_ptr = nullptr;
  bool result = table_->InsertTuple(&tuple, new_location_, txn,
                                    &index_entry_ptr);
  if (result == false) {
    txn_manager.SetTransactionResult(txn, ResultType::FAILURE);
    return;
  }
  txn_manager.PerformInsert(txn, new_location_, index_entry_ptr);
  executor_context_->num_processed++;
}

void Updater::TearDown() {
  // Updater object does not destruct its own data structures
  if (tile_ != nullptr) tile_.reset();
  delete target_list_;
}

}  // namespace codegen
}  // namespace peloton
<commit_msg>Correct use of c++ reset()<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// updater.cpp
//
// Identification: src/codegen/updater.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "codegen/updater.h"
#include "codegen/transaction_runtime.h"
#include "common/container_tuple.h"
#include "concurrency/transaction_manager_factory.h"
#include "executor/executor_context.h"
#include "storage/data_table.h"
#include "storage/tile_group_header.h"
#include "storage/tile_group.h"
#include "storage/tile.h"
#include "storage/tuple.h"
#include "type/abstract_pool.h"
#include "type/types.h"
#include "type/value.h"

namespace peloton {
namespace codegen {

void Updater::Init(storage::DataTable *table,
                   executor::ExecutorContext *executor_context,
                   Target *target_vector, uint32_t target_vector_size) {
  PL_ASSERT(table != nullptr && executor_context != nullptr&&
            target_vector != nullptr);
  table_ = table;
  executor_context_ = executor_context;
  // Target list is kept since it is required at a new version update
  target_list_ =
      new TargetList(target_vector, target_vector + target_vector_size);
}

char *Updater::GetDataPtr(uint32_t tile_group_id, uint32_t tuple_offset) {
  auto tile_group = table_->GetTileGroupById(tile_group_id);

  // Get the tile offset assuming that it is still in a tuple format
  oid_t tile_offset, tile_column_offset;
  tile_group->LocateTileAndColumn(0, tile_offset, tile_column_offset);
  tile_ = tile_group->GetTileReference(tile_offset);
  return tile_->GetTupleLocation(tuple_offset);
}

char *Updater::Prepare(uint32_t tile_group_id, uint32_t tuple_offset) {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(tile_group_id).get();
  auto *tile_group_header = tile_group->GetHeader();
  old_location_.block = tile_group_id;
  old_location_.offset = tuple_offset;

  // If I am the owner, update in-place
  is_owner_ = TransactionRuntime::IsOwner(*txn, tile_group_header,
                                          tuple_offset);
  if (is_owner_ == true)
    return GetDataPtr(tile_group_id, tuple_offset);

  // If not the owner, acquire ownership and build a new version tuple
  acquired_ownership_ = TransactionRuntime::AcquireOwnership(*txn,
      tile_group_header, tuple_offset);
  if (acquired_ownership_ == false)
    return nullptr;

  new_location_ = table_->AcquireVersion();
  return GetDataPtr(new_location_.block, new_location_.offset);
}

char *Updater::PreparePK(uint32_t tile_group_id, uint32_t tuple_offset) {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(tile_group_id).get();
  auto *tile_group_header = tile_group->GetHeader();

  // Check ownership
  is_owner_ = TransactionRuntime::IsOwner(*txn, tile_group_header,
                                          tuple_offset);
  acquired_ownership_ = false;
  if (is_owner_ == false) {
    acquired_ownership_ = TransactionRuntime::AcquireOwnership(
        *txn, tile_group_header, tuple_offset);
    if (acquired_ownership_ == false)
      return nullptr;
  }

  // Delete the old tuple
  ItemPointer old_location(tile_group_id, tuple_offset);
  ItemPointer empty_location = table_->InsertEmptyVersion();
  if (empty_location.IsNull() == true && acquired_ownership_ == true) {
    TransactionRuntime::YieldOwnership(*txn, tile_group_header,
                                       tuple_offset);
    return nullptr;
  }
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  txn_manager.PerformDelete(txn, old_location, empty_location);

  // Get the tuple data pointer for a new version
  new_location_ = table_->GetEmptyTupleSlot(nullptr);
  return GetDataPtr(new_location_.block, new_location_.offset);
}

peloton::type::AbstractPool *Updater::GetPool() {
  // This should be called after Prepare() or PreparePK()
  PL_ASSERT(tile_);
  return tile_->GetPool();
}

void Updater::Update() {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  LOG_TRACE("Updating tuple <%u, %u> from table '%s' (db ID: %u, table ID: %u)",
            old_location_.block, old_location_.offset,
            table_->GetName().c_str(), table_->GetDatabaseOid(),
            table_->GetOid());
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(old_location_.block).get();
  auto *tile_group_header = tile_group->GetHeader();
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();

  // Either update in-place
  if (is_owner_ == true) {
    txn_manager.PerformUpdate(txn, old_location_);
    executor_context_->num_processed++;
    return;
  }

  // Or, update with a new version
  ContainerTuple<storage::TileGroup> new_tuple(
    table_->GetTileGroupById(new_location_.block).get(), new_location_.offset);
  ItemPointer *indirection =
      tile_group_header->GetIndirection(old_location_.offset);
  auto result = table_->InstallVersion(&new_tuple, target_list_, txn,
                                       indirection);
  if (result == false) {
    TransactionRuntime::YieldOwnership(*txn, tile_group_header,
                                       old_location_.offset);
    return;
  }
  txn_manager.PerformUpdate(txn, old_location_, new_location_);
  executor_context_->num_processed++;
}

void Updater::UpdatePK() {
  PL_ASSERT(table_ != nullptr && executor_context_ != nullptr);
  LOG_TRACE("Updating tuple <%u, %u> from table '%s' (db ID: %u, table ID: %u)",
            old_location_.block, old_location_.offset,
            table_->GetName().c_str(), table_->GetDatabaseOid(),
            table_->GetOid());
  auto *txn = executor_context_->GetTransaction();
  auto tile_group = table_->GetTileGroupById(new_location_.block).get();
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();

  // Insert a new tuple
  ContainerTuple<storage::TileGroup> tuple(tile_group, new_location_.offset);
  ItemPointer *index_entry_ptr = nullptr;
  bool result = table_->InsertTuple(&tuple, new_location_, txn,
                                    &index_entry_ptr);
  if (result == false) {
    txn_manager.SetTransactionResult(txn, ResultType::FAILURE);
    return;
  }
  txn_manager.PerformInsert(txn, new_location_, index_entry_ptr);
  executor_context_->num_processed++;
}

void Updater::TearDown() {
  // Updater object does not destruct its own data structures
  tile_.reset();
  delete target_list_;
}

}  // namespace codegen
}  // namespace peloton
<|endoftext|>


<commit_before>/* This file is part of the KDE project
   Copyright 2008 Thomas McGuire <mcguire@kde.org>

   This library is free software; you can redistribute it and/or modify
   it under the terms of the GNU Library General Public License as published
   by the Free Software Foundation; either version 2 of the License or
   ( at your option ) version 3 or, at the discretion of KDE e.V.
   ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version.

   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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "qtest_kde.h"
#include "summaryeventtest.h"
#include "../summaryeventinfo.h"

#include <kcal/event.h>
#include <kcal/calendarlocal.h>

QTEST_KDEMAIN_CORE( SummaryEventTester )

void SummaryEventTester::test_Multiday()
{
  QDate today = QDate::currentDate();
  QString multidayWithTimeInProgress = "Multiday, time specified, in progress";

  KCal::CalendarLocal *cal = new KCal::CalendarLocal( KDateTime().timeSpec() );

  KCal::Event *event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( -1 ) ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ) ) );
  event->setSummary( "Multiday, allday, in progress (day 2/6)" );
  QVERIFY( cal->addEvent( event ) );

  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( -1 ), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ), QTime::fromString("12:00","hh:mm") ) );
  event->setSummary( multidayWithTimeInProgress  );
  QVERIFY( cal->addEvent( event ) );
    for ( int i = 0; i < 5; i++ ) {
    SummaryEventInfo::List events4 = SummaryEventInfo::eventsForDate( today.addDays( i ), cal );
    QCOMPARE( 1, events4.size() );
    SummaryEventInfo *ev4 = events4.at(0);

    QCOMPARE( ev4->summaryText, QString(multidayWithTimeInProgress + " (%1/7)").arg(i+2));
    QCOMPARE( ev4->timeRange, QString("00:00 - 23:59") );
//    QCOMPARE( ev4->startDate, KGlobal::locale()->formatDate( QDate( today.addDays( i ) ), KLocale::FancyLongDate ) );
    QCOMPARE( ev4->makeBold, i == 0 );

    qDeleteAll( events4 );
  }

  // Test date a multiday event in the future has to correct DaysTo set
  QString multiDayWithTimeFuture = "Multiday, with time, in the future";
  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( 100 ), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( 106 ), QTime::fromString("12:00","hh:mm") ) );
  event->setSummary( multiDayWithTimeFuture );
  QVERIFY( cal->addEvent( event ) );
  for ( int i = 100; i <= 106; i++ ) {
    SummaryEventInfo::List events5 = SummaryEventInfo::eventsForDate( today.addDays( i ), cal );
    QCOMPARE( 1, events5.size() );
    SummaryEventInfo *ev5 = events5.at(0);
    /*qDebug() << ev5->summaryText;
    qDebug() << ev5->daysToGo;
    qDebug() << i;*/

    QCOMPARE( ev5->summaryText, QString(multiDayWithTimeFuture + " (%1/7)").arg(i-100+1));
    QCOMPARE( ev5->daysToGo, QString("in %1 days").arg(i) );

    qDeleteAll( events5 );
  }

  QString multiDayAllDayInFuture = "Multiday, allday, in future";
  int multiDayFuture = 30;
  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( multiDayFuture ) ) );
  event->setDtEnd( KDateTime( today.addDays( multiDayFuture + 5 ) ) );
  event->setSummary( multiDayAllDayInFuture );
  QVERIFY( cal->addEvent( event ) );

  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( 2 ), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ), QTime::fromString("12:00","hh:mm") ) );
  event->setSummary( "Multiday, time specified, in future" );
  QVERIFY( cal->addEvent( event ) );

  QString multiDayAllDayStartingToday = "Multiday, allday, starting today";
  event = new KCal::Event();
  event->setDtStart( KDateTime( today ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ) ) );
  event->setSummary( multiDayAllDayStartingToday );
  QVERIFY( cal->addEvent( event ) );

  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays(-10), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( -5 ), QTime::fromString("10:00","hh:mm") ) );
  event->setSummary( "Some event in the past" );
  QVERIFY( cal->addEvent( event ) );

  SummaryEventInfo::List eventsToday = SummaryEventInfo::eventsForDate( today, cal );
  QCOMPARE( 2, eventsToday.size() );
  SummaryEventInfo *ev1 = eventsToday.at( 0 );
  QCOMPARE( ev1->summaryText, multidayWithTimeInProgress + " (2/7)");
  QCOMPARE( ev1->timeRange, QString("00:00 - 23:59") );
  QCOMPARE( ev1->startDate, QString("Today") );
  QCOMPARE( ev1->daysToGo, QString("now") );
  QCOMPARE( ev1->makeBold, true );
  SummaryEventInfo *ev2 = eventsToday.at( 1 );
  QCOMPARE( ev2->summaryText, multiDayAllDayStartingToday );
  QVERIFY( ev2->timeRange.isEmpty() );
  QCOMPARE( ev2->startDate, QString("Today") );
  QCOMPARE( ev2->daysToGo, QString("now") );
  QCOMPARE( ev2->makeBold, true );

  SummaryEventInfo::List events2 = SummaryEventInfo::eventsForDate( today.addDays( multiDayFuture ), cal );
  QCOMPARE( 1, events2.size() );
  ev1 = events2.at( 0 );
  QCOMPARE( ev1->summaryText, multiDayAllDayInFuture );
  QVERIFY( ev1->timeRange.isEmpty() );
  QCOMPARE( ev1->startDate, KGlobal::locale()->formatDate( QDate( today.addDays( multiDayFuture ) ) ) );
  QCOMPARE( ev1->daysToGo, QString("in %1 days").arg(multiDayFuture) );
  QCOMPARE( ev1->makeBold, false );
  // Make sure multiday is only displayed once
  for ( int i = 1; i < 30; i++ ) {
    SummaryEventInfo::List events3 = SummaryEventInfo::eventsForDate( today.addDays( multiDayFuture + i ), cal );
    foreach(SummaryEventInfo *ev, events3 ) {
      QVERIFY( ev->summaryText.contains( multiDayAllDayInFuture ) );
    }
    qDeleteAll( events3 );
  }

  qDeleteAll( eventsToday );
  qDeleteAll( events2 );
  delete cal;

}
<commit_msg>Fix the unit test, apparently the list of events can be abitrary. No idea for how long this has been broken...<commit_after>/* This file is part of the KDE project
   Copyright 2008 Thomas McGuire <mcguire@kde.org>

   This library is free software; you can redistribute it and/or modify
   it under the terms of the GNU Library General Public License as published
   by the Free Software Foundation; either version 2 of the License or
   ( at your option ) version 3 or, at the discretion of KDE e.V.
   ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version.

   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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "qtest_kde.h"
#include "summaryeventtest.h"
#include "../summaryeventinfo.h"

#include <kcal/event.h>
#include <kcal/calendarlocal.h>

QTEST_KDEMAIN_CORE( SummaryEventTester )

void SummaryEventTester::test_Multiday()
{
  QDate today = QDate::currentDate();
  QString multidayWithTimeInProgress = "Multiday, time specified, in progress";

  KCal::CalendarLocal *cal = new KCal::CalendarLocal( KDateTime().timeSpec() );

  KCal::Event *event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( -1 ) ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ) ) );
  event->setSummary( "Multiday, allday, in progress (day 2/6)" );
  QVERIFY( cal->addEvent( event ) );

  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( -1 ), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ), QTime::fromString("12:00","hh:mm") ) );
  event->setSummary( multidayWithTimeInProgress  );
  QVERIFY( cal->addEvent( event ) );
    for ( int i = 0; i < 5; i++ ) {
    SummaryEventInfo::List events4 = SummaryEventInfo::eventsForDate( today.addDays( i ), cal );
    QCOMPARE( 1, events4.size() );
    SummaryEventInfo *ev4 = events4.at(0);

    QCOMPARE( ev4->summaryText, QString(multidayWithTimeInProgress + " (%1/7)").arg(i+2));
    QCOMPARE( ev4->timeRange, QString("00:00 - 23:59") );
//    QCOMPARE( ev4->startDate, KGlobal::locale()->formatDate( QDate( today.addDays( i ) ), KLocale::FancyLongDate ) );
    QCOMPARE( ev4->makeBold, i == 0 );

    qDeleteAll( events4 );
  }

  // Test date a multiday event in the future has to correct DaysTo set
  QString multiDayWithTimeFuture = "Multiday, with time, in the future";
  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( 100 ), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( 106 ), QTime::fromString("12:00","hh:mm") ) );
  event->setSummary( multiDayWithTimeFuture );
  QVERIFY( cal->addEvent( event ) );
  for ( int i = 100; i <= 106; i++ ) {
    SummaryEventInfo::List events5 = SummaryEventInfo::eventsForDate( today.addDays( i ), cal );
    QCOMPARE( 1, events5.size() );
    SummaryEventInfo *ev5 = events5.at(0);
    /*qDebug() << ev5->summaryText;
    qDebug() << ev5->daysToGo;
    qDebug() << i;*/

    QCOMPARE( ev5->summaryText, QString(multiDayWithTimeFuture + " (%1/7)").arg(i-100+1));
    QCOMPARE( ev5->daysToGo, QString("in %1 days").arg(i) );

    qDeleteAll( events5 );
  }

  QString multiDayAllDayInFuture = "Multiday, allday, in future";
  int multiDayFuture = 30;
  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( multiDayFuture ) ) );
  event->setDtEnd( KDateTime( today.addDays( multiDayFuture + 5 ) ) );
  event->setSummary( multiDayAllDayInFuture );
  QVERIFY( cal->addEvent( event ) );

  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays( 2 ), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ), QTime::fromString("12:00","hh:mm") ) );
  event->setSummary( "Multiday, time specified, in future" );
  QVERIFY( cal->addEvent( event ) );

  QString multiDayAllDayStartingToday = "Multiday, allday, starting today";
  event = new KCal::Event();
  event->setDtStart( KDateTime( today ) );
  event->setDtEnd( KDateTime( today.addDays( 5 ) ) );
  event->setSummary( multiDayAllDayStartingToday );
  QVERIFY( cal->addEvent( event ) );

  event = new KCal::Event();
  event->setDtStart( KDateTime( today.addDays(-10), QTime::fromString("12:00","hh:mm") ) );
  event->setDtEnd( KDateTime( today.addDays( -5 ), QTime::fromString("10:00","hh:mm") ) );
  event->setSummary( "Some event in the past" );
  QVERIFY( cal->addEvent( event ) );

  SummaryEventInfo::List eventsToday = SummaryEventInfo::eventsForDate( today, cal );
  QCOMPARE( 2, eventsToday.size() );
  foreach( const SummaryEventInfo *ev, eventsToday ) {
    if ( ev->summaryText == multidayWithTimeInProgress + " (2/7)" ) {
      QCOMPARE( ev->timeRange, QString("00:00 - 23:59") );
      QCOMPARE( ev->startDate, QString("Today") );
      QCOMPARE( ev->daysToGo, QString("now") );
      QCOMPARE( ev->makeBold, true );
    }
    else if ( ev->summaryText == multiDayAllDayStartingToday ) {
      QVERIFY( ev->timeRange.isEmpty() );
      QCOMPARE( ev->startDate, QString("Today") );
      QCOMPARE( ev->daysToGo, QString("now") );
      QCOMPARE( ev->makeBold, true );
    }
    else
      Q_ASSERT( false ); // unexpected event!
  }

  SummaryEventInfo::List events2 = SummaryEventInfo::eventsForDate( today.addDays( multiDayFuture ), cal );
  QCOMPARE( 1, events2.size() );
  SummaryEventInfo *ev1 = events2.at( 0 );
  QCOMPARE( ev1->summaryText, multiDayAllDayInFuture );
  QVERIFY( ev1->timeRange.isEmpty() );
  QCOMPARE( ev1->startDate, KGlobal::locale()->formatDate( QDate( today.addDays( multiDayFuture ) ) ) );
  QCOMPARE( ev1->daysToGo, QString("in %1 days").arg(multiDayFuture) );
  QCOMPARE( ev1->makeBold, false );
  // Make sure multiday is only displayed once
  for ( int i = 1; i < 30; i++ ) {
    SummaryEventInfo::List events3 = SummaryEventInfo::eventsForDate( today.addDays( multiDayFuture + i ), cal );
    foreach(SummaryEventInfo *ev, events3 ) {
      QVERIFY( ev->summaryText.contains( multiDayAllDayInFuture ) );
    }
    qDeleteAll( events3 );
  }

  qDeleteAll( eventsToday );
  qDeleteAll( events2 );
  delete cal;

}
<|endoftext|>


<commit_before>/**
 * @file   AvailableSoftware.C
 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
 * @date   Tue Oct 16 17:54:11 2012
 *
 * @brief  Find available packages
 *
 * @ingroup pwglf_forward_trains_util
 */

#ifndef AVAILABLESOFTWARE_C
#define AVAILABLESOFTWARE_C
#ifndef __CINT__
# include <TString.h>
# include <TSystem.h>
# include <TError.h>
# include <TObjArray.h>
#else
class TString;
#endif

/**
 * Helper code to find available packages on Grid
 *
 *
 * @ingroup pwglf_forward_trains_util
 */
struct AvailableSoftware
{
  static Bool_t Check(TString& aliroot, TString& root, Bool_t debug=false)
  {
    // Figure out what to do.
    // If mode == 0, then do nothing.
    // If bit 0 is set in mode (0x1), then list and exit
    // If bit 1 is set in mode (0x2), select last AliROOT/ROOT version
    // If bit 2 is set in mode (0x4), select ROOT corresponding to AliROOT
    UShort_t mode = 0;

    Bool_t show = (aliroot.Contains("list", TString::kIgnoreCase) ||
		   root.Contains(   "list", TString::kIgnoreCase));
    Bool_t last = (aliroot.Contains("last", TString::kIgnoreCase) ||
		   aliroot.Contains("newest", TString::kIgnoreCase));
    Bool_t nots = (aliroot.Contains("nonspecial", TString::kIgnoreCase) ||
		   aliroot.Contains("regular",    TString::kIgnoreCase) ||
		   aliroot.Contains("standard",   TString::kIgnoreCase));
    Bool_t rele = (aliroot.Contains("release",    TString::kIgnoreCase));
    Bool_t anat = (aliroot.Contains("analysis",   TString::kIgnoreCase));

    TString c("wget -q http://alimonitor.cern.ch/packages/ -O - | "
	      "sed -n -e '/<tr/,/<\\/tr>/ p' | ");
    if (rele || anat || nots) {
      c.Append("sed -n '/<a.*VO_ALICE@AliRoot::v[0-9]\\{1,\\}-[0-9]\\{1,\\}-");
      if (rele)
	c.Append("Rev-[0-9]\\{1,\\}");
      else if (anat)
	c.Append("[0-9]\\{1,\\}-AN");
      else if (nots)
	c.Append("\\([0-9]\\{1,\\}\\|Rev\\)-\\(AN\\|[0-9]\\{1,\\}\\)");
      c.Append("/,/VO_ALICE@ROOT::/ p' | ");
    }
    else
      c.Append("sed -n '/<a.*VO_ALICE@AliRoot::/,/VO_ALICE@ROOT::/ p' | ");

    c.Append("sed -n -e 's/.*VO_ALICE@AliRoot::\\([-0-9a-zA-Z]*\\).*/%\\1%/p' "
	     "  -e 's/.*VO_ALICE@ROOT::\\([-0-9a-zA-Z]*\\).*/\\1@/p' | "
	     "tr -d '\\n' | tr '@' '\\n' | tr '%' '\\t' ");

    if (debug)
      Printf("Command: %s", c.Data());

    if (show || aliroot.IsNull()) {
      Warning("AvaliableSoftware::Check", "No AliROOT/ROOT version specified, "
	      "available packages are:\n"
	      "\tAliROOT \tROOT:");
      gSystem->Exec(c);
      return false;
    }

    if (last)
      mode |= 0x2;
    else if (!aliroot.IsNull())
      mode |= 0x4;

    // Nothing to do
    if (mode == 0) return true;

    if (debug) Printf("Mode=0x%02x", mode);

    TString    values = gSystem->GetFromPipe(c);
    TObjArray* tokens = values.Tokenize(" \t\n");
    Int_t      n      = tokens->GetEntries();

    // If we asked to select the last possible version, do so here and get out
    if (mode & 0x2) {
      aliroot = tokens->At(n-2)->GetName();
      root    = tokens->At(n-1)->GetName();
      Info("AvaliableSoftware::Check",
	   "Selecting lastest possible AliROOT/ROOT: %s/%s",
	   aliroot.Data(), root.Data());
      delete tokens;
      return true;
    }

    // We get here if we're asked to find a ROOT version compatible
    // with the selected AliROOT version.
    for (Int_t i = 0; i < n; i += 2) {
      if (aliroot.EqualTo(tokens->At(i)->GetName(),
				  TString::kIgnoreCase)) {
	root = tokens->At(i+1)->GetName();
	Info("AvaliableSoftware::Check",
	     "Found ROOT version compatible with AliROOT %s: %s",
	     aliroot.Data(), root.Data());
	delete tokens;
	return true;
      }
    }
    // If we get here, then we didn't find a ROOT version compatible
    // with the selected AliROOT, and we should fail.
    Warning("AvaliableSoftware::Check",
	    "Didn't find a ROOT version compatible with AliROOT %s",
	    aliroot.Data());
    delete tokens;
    return false;
  }
  static void Test(const TString& ali, const TString& roo=TString())
  {
    TString aliroot(Form("list,%s",ali.Data()));
    TString root(roo);
    Printf("Checking with AliROOT=%s ROOT=%s", ali.Data(), roo.Data());
    AvailableSoftware::Check(aliroot, root);

    aliroot = Form("last,%s",ali.Data());
    AvailableSoftware::Check(aliroot, root);
    Printf("Got AliROOT=%s ROOT=%s", aliroot.Data(), root.Data());
  }

  static void Test()
  {
    Printf("All available");
    AvailableSoftware::Test("");
    Printf("All regular");
    AvailableSoftware::Test("regular");
    Printf("All releases");
    AvailableSoftware::Test("release");
    Printf("All analysis tags");
    AvailableSoftware::Test("analysis");
  }
};
#endif
<commit_msg>Update for newer package name<commit_after>/**
 * @file   AvailableSoftware.C
 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
 * @date   Tue Oct 16 17:54:11 2012
 *
 * @brief  Find available packages
 *
 * @ingroup pwglf_forward_trains_util
 */

#ifndef AVAILABLESOFTWARE_C
#define AVAILABLESOFTWARE_C
#ifndef __CINT__
# include <TString.h>
# include <TSystem.h>
# include <TError.h>
# include <TObjArray.h>
#else
class TString;
#endif

/**
 * Helper code to find available packages on Grid
 *
 *
 * @ingroup pwglf_forward_trains_util
 */
struct AvailableSoftware
{
  static Bool_t Check(TString& aliroot, TString& root, Bool_t debug=false)
  {
    // Figure out what to do.
    // If mode == 0, then do nothing.
    // If bit 0 is set in mode (0x1), then list and exit
    // If bit 1 is set in mode (0x2), select last AliROOT/ROOT version
    // If bit 2 is set in mode (0x4), select ROOT corresponding to AliROOT
    UShort_t mode = 0;

    Bool_t show = (aliroot.Contains("list", TString::kIgnoreCase) ||
		   root.Contains(   "list", TString::kIgnoreCase));
    Bool_t last = (aliroot.Contains("last", TString::kIgnoreCase) ||
		   aliroot.Contains("newest", TString::kIgnoreCase));
    Bool_t nots = (aliroot.Contains("nonspecial", TString::kIgnoreCase) ||
		   aliroot.Contains("regular",    TString::kIgnoreCase) ||
		   aliroot.Contains("standard",   TString::kIgnoreCase));
    Bool_t rele = (aliroot.Contains("release",    TString::kIgnoreCase));
    Bool_t anat = (aliroot.Contains("analysis",   TString::kIgnoreCase));

    TString c("wget -q http://alimonitor.cern.ch/packages/ -O - | "
	      "sed -n -e '/<tr/,/<\\/tr>/ p' | ");
#if 0
    if (rele || anat || nots) {
      c.Append("sed -n '/<a.*VO_ALICE@AliRoot::v[0-9]\\{1,\\}-[0-9]\\{1,\\}-");
      if (rele)
	c.Append("Rev-[0-9]\\{1,\\}");
      else if (anat)
	c.Append("[0-9]\\{1,\\}-AN");
      else if (nots)
	c.Append("\\([0-9]\\{1,\\}\\|Rev\\)-\\(AN\\|[0-9]\\{1,\\}\\)");
      c.Append("/,/VO_ALICE@ROOT::/ p' | ");
    }
    else
      c.Append("sed -n '/<a.*VO_ALICE@AliRoot::/,/VO_ALICE@ROOT::/ p' | ");
#else
    if (rele || anat || nots) {
      c.Append("sed -n '/<a.*VO_ALICE@AliRoot::v");
      const char* relPat = "[0-9]\\{1,\\}-[0-9]\\{1,\\}-Rev-[0-9]\\{1,\\}";
      const char* anaPat = "AN-[0-9]\\{8,\\}";
      if      (rele) 	c.Append(relPat);
      else if (anat)  	c.Append(anaPat);
      else if (nots)    c.Append(Form("\\(%s\\|%s\\)", relPat, anaPat));
      c.Append("/,/VO_ALICE@ROOT::/ p' | ");
    }
    else
      c.Append("sed -n '/<a.*VO_ALICE@AliRoot::/,/VO_ALICE@ROOT::/ p' | ");
#endif

    c.Append("sed -n -e 's/.*VO_ALICE@AliRoot::\\([-0-9a-zA-Z]*\\).*/%\\1%/p' "
	     "  -e 's/.*VO_ALICE@ROOT::\\([-0-9a-zA-Z]*\\).*/\\1@/p' | "
	     "tr -d '\\n' | tr '@' '\\n' | tr '%' '\\t' ");

    if (debug)
      Printf("Command: %s", c.Data());

    if (show || aliroot.IsNull()) {
      Warning("AvaliableSoftware::Check", "No AliROOT/ROOT version specified, "
	      "available packages are:\n"
	      "\tAliROOT \tROOT:");
      gSystem->Exec(c);
      return false;
    }

    if (last)
      mode |= 0x2;
    else if (!aliroot.IsNull())
      mode |= 0x4;

    // Nothing to do
    if (mode == 0) return true;

    if (debug) Printf("Mode=0x%02x", mode);

    TString    values = gSystem->GetFromPipe(c);
    TObjArray* tokens = values.Tokenize(" \t\n");
    Int_t      n      = tokens->GetEntries();

    // If we asked to select the last possible version, do so here and get out
    if (mode & 0x2) {
      aliroot = tokens->At(n-2)->GetName();
      root    = tokens->At(n-1)->GetName();
      Info("AvaliableSoftware::Check",
	   "Selecting lastest possible AliROOT/ROOT: %s/%s",
	   aliroot.Data(), root.Data());
      delete tokens;
      return true;
    }

    // We get here if we're asked to find a ROOT version compatible
    // with the selected AliROOT version.
    for (Int_t i = 0; i < n; i += 2) {
      if (aliroot.EqualTo(tokens->At(i)->GetName(),
				  TString::kIgnoreCase)) {
	root = tokens->At(i+1)->GetName();
	Info("AvaliableSoftware::Check",
	     "Found ROOT version compatible with AliROOT %s: %s",
	     aliroot.Data(), root.Data());
	delete tokens;
	return true;
      }
    }
    // If we get here, then we didn't find a ROOT version compatible
    // with the selected AliROOT, and we should fail.
    Warning("AvaliableSoftware::Check",
	    "Didn't find a ROOT version compatible with AliROOT %s",
	    aliroot.Data());
    delete tokens;
    return false;
  }
  static void Test(const TString& ali, const TString& roo=TString())
  {
    TString aliroot(Form("list,%s",ali.Data()));
    TString root(roo);
    Printf("Checking with AliROOT=%s ROOT=%s", ali.Data(), roo.Data());
    AvailableSoftware::Check(aliroot, root);

    aliroot = Form("last,%s",ali.Data());
    AvailableSoftware::Check(aliroot, root);
    Printf("Got AliROOT=%s ROOT=%s", aliroot.Data(), root.Data());
  }

  static void Test()
  {
    Printf("All available");
    AvailableSoftware::Test("");
    Printf("All regular");
    AvailableSoftware::Test("regular");
    Printf("All releases");
    AvailableSoftware::Test("release");
    Printf("All analysis tags");
    AvailableSoftware::Test("analysis");
  }
};
#endif
<|endoftext|>