<commit_before>/* -*- Mode: C++; indent-tabs-mode: nil -*- */
#include "_python.h"

#include <fstream>
#include <memory>

#include <schwa/_base.h>
#include <schwa/exception.h>
#include <schwa/tokenizer.h>
#include <schwa/utils/enums.h>

#include "callback_stream.h"
#include "exception.h"
#include "pystream.h"
#include "seq_stream.h"
#include "text_stream.h"

namespace io = schwa::io;
namespace tok = schwa::tokenizer;

using schwa::to_underlying;

// ============================================================================
// Module-level objects
// ============================================================================
static PyObject *module_TokenError = nullptr;

// ============================================================================
// PyTokenizer
// ============================================================================
typedef struct {
  PyObject_HEAD
  tok::Tokenizer *tokenizer;
} PyTokenizer;

static PyObject *
PyTokenizer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
  PyTokenizer *self = (PyTokenizer *)type->tp_alloc(type, 0);
  if (self != nullptr)
    self->tokenizer = new tok::Tokenizer();
  return (PyObject *)self;
}

static void
PyTokenizer_dealloc(PyTokenizer *self) {
  PyObject *const pyself = (PyObject *)self;
  delete self->tokenizer;
  pyself->ob_type->tp_free(pyself);
}

static const char *const PyTokenizer_tokenize__doc =
  "Identifies paragraph, sentence and token boundaries in (English) text or HTML,\n"
  "using a rule-based lexer.\n"
  "\n"
  "Arguments:\n"
  "\n"
  "  source: a UTF-8 byte string\n"
  "\n"
  "  dest: the output method, one of the following Python types:\n"
  "    - str (default): outputs a UTF-8 string with '\\n\\n', '\\n' and ' ' as\n"
  "      paragraph, sentence and token delimiters respectively\n"
  "    - unicode: like str, but with UTF-8 decoded\n"
  "    - list: outputs a list of paragraphs, each containing a list of sentences,\n"
  "      each containing a list of (offset, raw_token, [normalised_token]) tuples\n"
  "    or:\n"
  "    - any other callable: makes callbacks with arguments\n"
  "      (emit_type, offset, raw, norm)\n"
  "    - any other object: calls methods named according to emit_type when present\n"
  "\n"
  "    Offset is a byte offset into the input string.\n"
  "    Emit types are:\n"
  "      begin_{document,paragraph,sentence,heading,list,item},\n"
  "      end_{document,paragraph,sentence,heading,list,item},\n"
  "      token and error\n"
  "\n"
  "  filename: the path to a file to use instead of source\n"
  "\n"
  "  buffer_size: \n"
  "\n"
  "  errors: a method for dealing with bad byte sequences, may be one of:\n"
  "    - ERROR_SKIP (default): ignores errors\n"
  "    - ERROR_CALL: emits ('error', offset, bytes)\n"
  "    - ERROR_THROW: throws a TokenError\n"
  "\n"
  "  normalise: a boolean (default True) indicating whether to perform\n"
  "    normalisation on the output (such as directed quotes, all dashes as --, and\n"
  "    * to indicate list items). Only applies when dest is str or unicode.\n"
  "\n"
  "  mmap: a boolean (default False) indicating whether to process the file\n"
  "    memory-mapped, when the filename argument is used.";

PyObject *
PyTokenizer_tokenize(PyTokenizer *self, PyObject *args, PyObject *kwargs) {
  // Setup default values for kwarg parsing.
  PyObject *pysrc = nullptr;
  PyObject *pydest = (PyObject *)&SCHWA_PY_BYTES_TYPE;
  const char *filename = nullptr;
  Py_ssize_t buffer_size = static_cast<Py_ssize_t>(tok::DEFAULT_BUFFER_SIZE);
  int pyerrors = to_underlying(tok::OnError::SKIP);
  int normalise = 1;
  int use_mmap = 0;

  // Parse the kwargs.
  static const char *kwlist[] = {"source", "dest", "filename", "buffer_size", "errors", "normalise", "mmap", 0};
  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOsniii:tokenize", (char **)kwlist, &pysrc, &pydest, &filename, &buffer_size, &pyerrors, &normalise, &use_mmap))
    return 0;

  // Validate the arguments.
  if (!pysrc && !filename)
    return PyErr_Format(PyExc_TypeError, "tokenize() requires either a source or filename argument");
  if (pysrc) {
    if (PyUnicode_Check(pysrc))
      return PyErr_Format(PyExc_TypeError, "tokenize() does not accept unicode objects, use unicode.encode('utf-8')");
    else if (!SCHWA_PY_CHECK_BUFFER(pysrc))
      return PyErr_Format(PyExc_TypeError, "tokenize() source must support the buffer interface");
  }
  if (buffer_size <= 0)
    return PyErr_Format(PyExc_ValueError, "tokenize() buffer_size must be positive, %zu given", buffer_size);
  tok::OnError onerror = tok::OnError::SKIP;
  switch (pyerrors) {
  case to_underlying(tok::OnError::CALL):
    onerror = tok::OnError::CALL;
    break;
  case to_underlying(tok::OnError::SKIP):
    onerror = tok::OnError::SKIP;
    break;
  case to_underlying(tok::OnError::THROW):
    onerror = tok::OnError::THROW;
    break;
  default:
    return PyErr_Format(PyExc_ValueError, "tokenize() unknown bad byte error handler, %d given", pyerrors);
  }

  try {
    // Work out what the destination for the tokenizers output should be.
    std::unique_ptr<tok::PyStream> stream;
    if ((void *)pydest == (void *)&SCHWA_PY_BYTES_TYPE)
      stream.reset(new tok::PyBytesStream(normalise));
    else if ((void *)pydest == (void *)&PyUnicode_Type)
      stream.reset(new tok::PyUnicodeStream(normalise));
    else if ((void *)pydest == (void *)&PyList_Type)
      stream.reset(new tok::PyListStream());
    else if ((void *)pydest == (void *)&PyTuple_Type)
      stream.reset(new tok::PyTupleStream());
    else if (PyCallable_Check(pydest))
      stream.reset(new tok::PyCallFuncStream(pydest));
    else
      stream.reset(new tok::PyCallObjectStream(pydest));

    // Call the appropriate tokenize method on the Tokenizer object.
    if (filename) {
      if (use_mmap)
        self->tokenizer->tokenize_mmap(*stream, filename, onerror);
      else {
        std::ifstream in(filename);
        if (!in)
          return PyErr_Format(PyExc_IOError, "tokenize() could not open file '%s' for reading", filename);
        self->tokenizer->tokenize_stream(*stream, in, static_cast<size_t>(buffer_size), onerror);
      }
    }
    else {
      // Obtain the underlying buffer and pass it to the tokenizer, ensuring we release it.
      Py_buffer buffer;
      if (PyObject_GetBuffer(pysrc, &buffer, PyBUF_SIMPLE) != 0)
        return PyErr_Format(PyExc_ValueError, "tokenize() only supports simple buffer objects");
      if (buffer.len < 0)
        return PyErr_Format(PyExc_ValueError, "Size of the provided source's underlying buffer is negative");
      try {
        self->tokenizer->tokenize(*stream, (char *)buffer.buf, static_cast<size_t>(buffer.len), onerror);
      }
      catch (...) {
        PyBuffer_Release(&buffer);
        throw;
      }
    }

    // Return what the stream defines is the return value for this function.
    return stream->return_value();
  }
  catch (tok::TokenError &e) {
    PyErr_SetString(module_TokenError, e.what());
    return nullptr;
  }
  catch (tok::PyRaise &e) {
    return nullptr;
  }
  catch (schwa::IOException &e) {
    PyErr_SetString(PyExc_IOError, e.what());
    return nullptr;
  }
}

static PyMethodDef PyTokenizer_methods[] = {
  {"tokenize", (PyCFunction)PyTokenizer_tokenize, METH_VARARGS | METH_KEYWORDS, PyTokenizer_tokenize__doc},
  {nullptr}  /* Sentinel */
};

static PyTypeObject PyTokenizerType = {
  PyVarObject_HEAD_INIT(nullptr, 0)
  "tokenizer.Tokenizer",     /* tp_name */
  sizeof(PyTokenizer),       /* tp_basicsize */
  0,                         /* tp_itemsize */
  (destructor)PyTokenizer_dealloc,  /* tp_dealloc */
  0,                         /* tp_print */
  0,                         /* tp_getattr */
  0,                         /* tp_setattr */
  0,                         /* tp_compare */
  0,                         /* tp_repr */
  0,                         /* tp_as_number */
  0,                         /* tp_as_sequence */
  0,                         /* tp_as_mapping */
  0,                         /* tp_hash  */
  0,                         /* tp_call */
  0,                         /* tp_str */
  0,                         /* tp_getattro */
  0,                         /* tp_setattro */
  0,                         /* tp_as_buffer */
  Py_TPFLAGS_DEFAULT,        /* tp_flags */
  "Wrapper around the C++ Tokenizer class.",  /* tp_doc */
  0,                         /* tp_traverse */
  0,                         /* tp_clear */
  0,                         /* tp_richcompare */
  0,                         /* tp_weaklistoffset */
  0,                         /* tp_iter */
  0,                         /* tp_iternext */
  PyTokenizer_methods,       /* tp_methods */
  0,                         /* tp_members */
  0,                         /* tp_getset */
  0,                         /* tp_base */
  0,                         /* tp_dict */
  0,                         /* tp_descr_get */
  0,                         /* tp_descr_set */
  0,                         /* tp_dictoffset */
  (initproc)0,               /* tp_init */
  0,                         /* tp_alloc */
  PyTokenizer_new,           /* tp_new */
};

// ============================================================================
// Module
// ============================================================================
static const char *const module_name = "tokenizer";
static const char *const module_doc = "Schwa Lab tokenizer module";

static PyMethodDef module_methods[] = {
  {nullptr}  /* Sentinel */
};

#ifdef IS_PY3K
static PyModuleDef module_def = {
  PyModuleDef_HEAD_INIT,  /* m_base */
  module_name,            /* m_name */
  module_doc,             /* m_doc */
  0,                      /* m_size */
  module_methods,         /* m_methods */
  nullptr,                /* m_reload */
  nullptr,                /* m_traverse */
  nullptr,                /* m_clear */
  nullptr,                /* m_free */
};
#endif

static PyObject *
_inittokenizer(void) {
  // Ensure that PyTokenizerType is ready for use.
  if (PyType_Ready(&PyTokenizerType) != 0)
    return nullptr;

  // Construct the module.
#ifdef IS_PY3K
  PyObject *const m = PyModule_Create(&module_def);
#else
  PyObject *const m = Py_InitModule3(module_name, module_methods, module_doc);
#endif
  if (m == nullptr)
    return nullptr;

  // Add PyTokenizerType to the module.
  Py_INCREF(&PyTokenizerType);
  if (PyModule_AddObject(m, "Tokenizer", (PyObject *)&PyTokenizerType) != 0)
    return nullptr;

  // Create the TokenError exception and add it to the module.
  module_TokenError = PyErr_NewException((char *)"tokenizer.TokenError", nullptr, nullptr);
  if (module_TokenError == nullptr)
    return nullptr;
  Py_INCREF(&module_TokenError);
  if (PyModule_AddObject(m, "TokenError", module_TokenError) != 0)
    return nullptr;

  // Add the error handling enums to the module.
  if (PyModule_AddIntConstant(m, "ERROR_CALL", to_underlying(tok::OnError::CALL)) != 0)
    return nullptr;
  if (PyModule_AddIntConstant(m, "ERROR_SKIP", to_underlying(tok::OnError::SKIP)) != 0)
    return nullptr;
  if (PyModule_AddIntConstant(m, "ERROR_THROW", to_underlying(tok::OnError::THROW)) != 0)
    return nullptr;

  return m;
}

PyMODINIT_FUNC
#ifdef IS_PY3K
inittokenizer(void) {
#else
PyInit_tokenizer(void) {
#endif
  PyObject *const m = _inittokenizer();
  if (m == nullptr && PyErr_Occurred()) {
    PyErr_SetString(PyExc_ImportError, "tokenizer: init failed");
    SCHWA_PY_MODULE_INIT_RETURN_ERROR(m);
  }

  SCHWA_PY_MODULE_INIT_RETURN_SUCCESS(m);
}
<commit_msg>Corrected swapped module initialisation function names.<commit_after>/* -*- Mode: C++; indent-tabs-mode: nil -*- */
#include "_python.h"

#include <fstream>
#include <memory>

#include <schwa/_base.h>
#include <schwa/exception.h>
#include <schwa/tokenizer.h>
#include <schwa/utils/enums.h>

#include "callback_stream.h"
#include "exception.h"
#include "pystream.h"
#include "seq_stream.h"
#include "text_stream.h"

namespace io = schwa::io;
namespace tok = schwa::tokenizer;

using schwa::to_underlying;

// ============================================================================
// Module-level objects
// ============================================================================
static PyObject *module_TokenError = nullptr;

// ============================================================================
// PyTokenizer
// ============================================================================
typedef struct {
  PyObject_HEAD
  tok::Tokenizer *tokenizer;
} PyTokenizer;

static PyObject *
PyTokenizer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
  PyTokenizer *self = (PyTokenizer *)type->tp_alloc(type, 0);
  if (self != nullptr)
    self->tokenizer = new tok::Tokenizer();
  return (PyObject *)self;
}

static void
PyTokenizer_dealloc(PyTokenizer *self) {
  PyObject *const pyself = (PyObject *)self;
  delete self->tokenizer;
  pyself->ob_type->tp_free(pyself);
}

static const char *const PyTokenizer_tokenize__doc =
  "Identifies paragraph, sentence and token boundaries in (English) text or HTML,\n"
  "using a rule-based lexer.\n"
  "\n"
  "Arguments:\n"
  "\n"
  "  source: a UTF-8 byte string\n"
  "\n"
  "  dest: the output method, one of the following Python types:\n"
  "    - str (default): outputs a UTF-8 string with '\\n\\n', '\\n' and ' ' as\n"
  "      paragraph, sentence and token delimiters respectively\n"
  "    - unicode: like str, but with UTF-8 decoded\n"
  "    - list: outputs a list of paragraphs, each containing a list of sentences,\n"
  "      each containing a list of (offset, raw_token, [normalised_token]) tuples\n"
  "    or:\n"
  "    - any other callable: makes callbacks with arguments\n"
  "      (emit_type, offset, raw, norm)\n"
  "    - any other object: calls methods named according to emit_type when present\n"
  "\n"
  "    Offset is a byte offset into the input string.\n"
  "    Emit types are:\n"
  "      begin_{document,paragraph,sentence,heading,list,item},\n"
  "      end_{document,paragraph,sentence,heading,list,item},\n"
  "      token and error\n"
  "\n"
  "  filename: the path to a file to use instead of source\n"
  "\n"
  "  buffer_size: \n"
  "\n"
  "  errors: a method for dealing with bad byte sequences, may be one of:\n"
  "    - ERROR_SKIP (default): ignores errors\n"
  "    - ERROR_CALL: emits ('error', offset, bytes)\n"
  "    - ERROR_THROW: throws a TokenError\n"
  "\n"
  "  normalise: a boolean (default True) indicating whether to perform\n"
  "    normalisation on the output (such as directed quotes, all dashes as --, and\n"
  "    * to indicate list items). Only applies when dest is str or unicode.\n"
  "\n"
  "  mmap: a boolean (default False) indicating whether to process the file\n"
  "    memory-mapped, when the filename argument is used.";

PyObject *
PyTokenizer_tokenize(PyTokenizer *self, PyObject *args, PyObject *kwargs) {
  // Setup default values for kwarg parsing.
  PyObject *pysrc = nullptr;
  PyObject *pydest = (PyObject *)&SCHWA_PY_BYTES_TYPE;
  const char *filename = nullptr;
  Py_ssize_t buffer_size = static_cast<Py_ssize_t>(tok::DEFAULT_BUFFER_SIZE);
  int pyerrors = to_underlying(tok::OnError::SKIP);
  int normalise = 1;
  int use_mmap = 0;

  // Parse the kwargs.
  static const char *kwlist[] = {"source", "dest", "filename", "buffer_size", "errors", "normalise", "mmap", 0};
  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOsniii:tokenize", (char **)kwlist, &pysrc, &pydest, &filename, &buffer_size, &pyerrors, &normalise, &use_mmap))
    return 0;

  // Validate the arguments.
  if (!pysrc && !filename)
    return PyErr_Format(PyExc_TypeError, "tokenize() requires either a source or filename argument");
  if (pysrc) {
    if (PyUnicode_Check(pysrc))
      return PyErr_Format(PyExc_TypeError, "tokenize() does not accept unicode objects, use unicode.encode('utf-8')");
    else if (!SCHWA_PY_CHECK_BUFFER(pysrc))
      return PyErr_Format(PyExc_TypeError, "tokenize() source must support the buffer interface");
  }
  if (buffer_size <= 0)
    return PyErr_Format(PyExc_ValueError, "tokenize() buffer_size must be positive, %zu given", buffer_size);
  tok::OnError onerror = tok::OnError::SKIP;
  switch (pyerrors) {
  case to_underlying(tok::OnError::CALL):
    onerror = tok::OnError::CALL;
    break;
  case to_underlying(tok::OnError::SKIP):
    onerror = tok::OnError::SKIP;
    break;
  case to_underlying(tok::OnError::THROW):
    onerror = tok::OnError::THROW;
    break;
  default:
    return PyErr_Format(PyExc_ValueError, "tokenize() unknown bad byte error handler, %d given", pyerrors);
  }

  try {
    // Work out what the destination for the tokenizers output should be.
    std::unique_ptr<tok::PyStream> stream;
    if ((void *)pydest == (void *)&SCHWA_PY_BYTES_TYPE)
      stream.reset(new tok::PyBytesStream(normalise));
    else if ((void *)pydest == (void *)&PyUnicode_Type)
      stream.reset(new tok::PyUnicodeStream(normalise));
    else if ((void *)pydest == (void *)&PyList_Type)
      stream.reset(new tok::PyListStream());
    else if ((void *)pydest == (void *)&PyTuple_Type)
      stream.reset(new tok::PyTupleStream());
    else if (PyCallable_Check(pydest))
      stream.reset(new tok::PyCallFuncStream(pydest));
    else
      stream.reset(new tok::PyCallObjectStream(pydest));

    // Call the appropriate tokenize method on the Tokenizer object.
    if (filename) {
      if (use_mmap)
        self->tokenizer->tokenize_mmap(*stream, filename, onerror);
      else {
        std::ifstream in(filename);
        if (!in)
          return PyErr_Format(PyExc_IOError, "tokenize() could not open file '%s' for reading", filename);
        self->tokenizer->tokenize_stream(*stream, in, static_cast<size_t>(buffer_size), onerror);
      }
    }
    else {
      // Obtain the underlying buffer and pass it to the tokenizer, ensuring we release it.
      Py_buffer buffer;
      if (PyObject_GetBuffer(pysrc, &buffer, PyBUF_SIMPLE) != 0)
        return PyErr_Format(PyExc_ValueError, "tokenize() only supports simple buffer objects");
      if (buffer.len < 0)
        return PyErr_Format(PyExc_ValueError, "Size of the provided source's underlying buffer is negative");
      try {
        self->tokenizer->tokenize(*stream, (char *)buffer.buf, static_cast<size_t>(buffer.len), onerror);
      }
      catch (...) {
        PyBuffer_Release(&buffer);
        throw;
      }
    }

    // Return what the stream defines is the return value for this function.
    return stream->return_value();
  }
  catch (tok::TokenError &e) {
    PyErr_SetString(module_TokenError, e.what());
    return nullptr;
  }
  catch (tok::PyRaise &e) {
    return nullptr;
  }
  catch (schwa::IOException &e) {
    PyErr_SetString(PyExc_IOError, e.what());
    return nullptr;
  }
}

static PyMethodDef PyTokenizer_methods[] = {
  {"tokenize", (PyCFunction)PyTokenizer_tokenize, METH_VARARGS | METH_KEYWORDS, PyTokenizer_tokenize__doc},
  {nullptr}  /* Sentinel */
};

static PyTypeObject PyTokenizerType = {
  PyVarObject_HEAD_INIT(nullptr, 0)
  "tokenizer.Tokenizer",     /* tp_name */
  sizeof(PyTokenizer),       /* tp_basicsize */
  0,                         /* tp_itemsize */
  (destructor)PyTokenizer_dealloc,  /* tp_dealloc */
  0,                         /* tp_print */
  0,                         /* tp_getattr */
  0,                         /* tp_setattr */
  0,                         /* tp_compare */
  0,                         /* tp_repr */
  0,                         /* tp_as_number */
  0,                         /* tp_as_sequence */
  0,                         /* tp_as_mapping */
  0,                         /* tp_hash  */
  0,                         /* tp_call */
  0,                         /* tp_str */
  0,                         /* tp_getattro */
  0,                         /* tp_setattro */
  0,                         /* tp_as_buffer */
  Py_TPFLAGS_DEFAULT,        /* tp_flags */
  "Wrapper around the C++ Tokenizer class.",  /* tp_doc */
  0,                         /* tp_traverse */
  0,                         /* tp_clear */
  0,                         /* tp_richcompare */
  0,                         /* tp_weaklistoffset */
  0,                         /* tp_iter */
  0,                         /* tp_iternext */
  PyTokenizer_methods,       /* tp_methods */
  0,                         /* tp_members */
  0,                         /* tp_getset */
  0,                         /* tp_base */
  0,                         /* tp_dict */
  0,                         /* tp_descr_get */
  0,                         /* tp_descr_set */
  0,                         /* tp_dictoffset */
  (initproc)0,               /* tp_init */
  0,                         /* tp_alloc */
  PyTokenizer_new,           /* tp_new */
};

// ============================================================================
// Module
// ============================================================================
static const char *const module_name = "tokenizer";
static const char *const module_doc = "Schwa Lab tokenizer module";

static PyMethodDef module_methods[] = {
  {nullptr}  /* Sentinel */
};

#ifdef IS_PY3K
static PyModuleDef module_def = {
  PyModuleDef_HEAD_INIT,  /* m_base */
  module_name,            /* m_name */
  module_doc,             /* m_doc */
  0,                      /* m_size */
  module_methods,         /* m_methods */
  nullptr,                /* m_reload */
  nullptr,                /* m_traverse */
  nullptr,                /* m_clear */
  nullptr,                /* m_free */
};
#endif

static PyObject *
_inittokenizer(void) {
  // Ensure that PyTokenizerType is ready for use.
  if (PyType_Ready(&PyTokenizerType) != 0)
    return nullptr;

  // Construct the module.
#ifdef IS_PY3K
  PyObject *const m = PyModule_Create(&module_def);
#else
  PyObject *const m = Py_InitModule3(module_name, module_methods, module_doc);
#endif
  if (m == nullptr)
    return nullptr;

  // Add PyTokenizerType to the module.
  Py_INCREF(&PyTokenizerType);
  if (PyModule_AddObject(m, "Tokenizer", (PyObject *)&PyTokenizerType) != 0)
    return nullptr;

  // Create the TokenError exception and add it to the module.
  module_TokenError = PyErr_NewException((char *)"tokenizer.TokenError", nullptr, nullptr);
  if (module_TokenError == nullptr)
    return nullptr;
  Py_INCREF(&module_TokenError);
  if (PyModule_AddObject(m, "TokenError", module_TokenError) != 0)
    return nullptr;

  // Add the error handling enums to the module.
  if (PyModule_AddIntConstant(m, "ERROR_CALL", to_underlying(tok::OnError::CALL)) != 0)
    return nullptr;
  if (PyModule_AddIntConstant(m, "ERROR_SKIP", to_underlying(tok::OnError::SKIP)) != 0)
    return nullptr;
  if (PyModule_AddIntConstant(m, "ERROR_THROW", to_underlying(tok::OnError::THROW)) != 0)
    return nullptr;

  return m;
}

PyMODINIT_FUNC
#ifdef IS_PY3K
PyInit_tokenizer(void) {
#else
inittokenizer(void) {
#endif
  PyObject *const m = _inittokenizer();
  if (m == nullptr && PyErr_Occurred()) {
    PyErr_SetString(PyExc_ImportError, "tokenizer: init failed");
    SCHWA_PY_MODULE_INIT_RETURN_ERROR(m);
  }

  SCHWA_PY_MODULE_INIT_RETURN_SUCCESS(m);
}
<|endoftext|>


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

#include "legion_terra_partitions.h"
#include "legion_terra_partitions_cxx.h"

#include "arrays.h"
#include "legion.h"
#include "legion_c_util.h"
#include "legion_utilities.h"
#include "lowlevel.h"
#include "utilities.h"

#ifdef SHARED_LOWLEVEL
#define USE_LEGION_CROSS_PRODUCT 1
#else
// General LLR can't handle new partion API yet.
#define USE_LEGION_CROSS_PRODUCT 0
#endif

#ifndef USE_TLS
// Mac OS X and GCC <= 4.7 do not support C++11 thread_local.
#if __cplusplus < 201103L || defined(__MACH__) || (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)))
#define USE_TLS 0
#else
#define USE_TLS 1
#endif
#endif

struct CachedIndexIterator {
public:
  CachedIndexIterator(HighLevelRuntime *rt, Context ctx, IndexSpace is, bool gl)
    : runtime(rt), context(ctx), space(is), index(0), cached(false), global(gl)
  {
  }

  bool has_next() {
    if (!cached) cache();
    return index < spans.size();
  }

  ptr_t next_span(size_t *count) {
    if (!cached) cache();
    if (index >= spans.size()) {
      *count = 0;
      return ptr_t::nil();
    }
    std::pair<ptr_t, size_t> span = spans[index++];
    *count = span.second;
    return span.first;
  }

  void reset() {
    index = 0;
  }

private:
  void cache() {
    assert(!cached);

    if (global) {
#if !USE_TLS
      LegionRuntime::HighLevel::AutoLock guard(global_lock);
#endif
      std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > >::iterator it =
        global_cache.find(space);
      if (it != global_cache.end()) {
        spans = it->second;
        cached = true;
        return;
      }
    }

    IndexIterator it(runtime, context, space);
    while (it.has_next()) {
      size_t count = 0;
      ptr_t start = it.next_span(count);
      assert(count && !start.is_null());
      spans.push_back(std::pair<ptr_t, size_t>(start, count));
    }

    if (global) {
#if USE_TLS
      global_cache[space] = spans;
#else
      LegionRuntime::HighLevel::AutoLock guard(global_lock);
      if (!global_cache.count(space)) {
        global_cache[space] = spans;
      }
#endif
    }

    cached = true;
  }

private:
  HighLevelRuntime *runtime;
  Context context;
  IndexSpace space;
  std::vector<std::pair<ptr_t, size_t> > spans;
  size_t index;
  bool cached;
  bool global;
private:
#if USE_TLS
  static thread_local
  std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > > global_cache;
#else
  static std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > > global_cache;
  static ImmovableLock global_lock;
#endif
};

#if USE_TLS
thread_local std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > >
  CachedIndexIterator::global_cache;
#else
std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > >
  CachedIndexIterator::global_cache;
ImmovableLock CachedIndexIterator::global_lock(true);
#endif

class TerraCObjectWrapper {
public:

#define NEW_OPAQUE_WRAPPER(T_, T)                                       \
      static T_ wrap(T t) {                                             \
        T_ t_;                                                          \
        t_.impl = static_cast<void *>(t);                               \
        return t_;                                                      \
      }                                                                 \
      static const T_ wrap_const(const T t) {                           \
        T_ t_;                                                          \
        t_.impl = const_cast<void *>(static_cast<const void *>(t));     \
        return t_;                                                      \
      }                                                                 \
      static T unwrap(T_ t_) {                                          \
        return static_cast<T>(t_.impl);                                 \
      }                                                                 \
      static const T unwrap_const(const T_ t_) {                        \
        return static_cast<const T>(t_.impl);                           \
      }

  NEW_OPAQUE_WRAPPER(legion_terra_cached_index_iterator_t, CachedIndexIterator *);
#undef NEW_OPAQUE_WRAPPER
};

void
create_cross_product(HighLevelRuntime *runtime,
                     Context ctx,
                     IndexPartition lhs,
                     IndexPartition rhs,
                     Color rhs_color /* = -1 */)
{
  if (rhs_color == (Color)-1) {
    rhs_color = runtime->get_index_partition_color(ctx, rhs);
  }

#if USE_LEGION_CROSS_PRODUCT
  std::map<DomainPoint, IndexPartition> handles;
  runtime->create_cross_product_partitions(
    ctx, lhs, rhs, handles,
    (runtime->is_index_partition_disjoint(ctx, rhs) ? DISJOINT_KIND : ALIASED_KIND),
    rhs_color, true);
#else
  // FIXME: Validate: same index tree

  Domain lhs_colors = runtime->get_index_partition_color_space(ctx, lhs);
  Domain rhs_colors = runtime->get_index_partition_color_space(ctx, rhs);

  for (Domain::DomainPointIterator lh_dp(lhs_colors); lh_dp; lh_dp++) {
    Color lh_color = lh_dp.p.get_point<1>()[0];
    IndexSpace lh_space = runtime->get_index_subspace(ctx, lhs, lh_color);

    Coloring lh_coloring;
    for (Domain::DomainPointIterator rh_dp(rhs_colors); rh_dp; rh_dp++) {
      Color rh_color = rh_dp.p.get_point<1>()[0];
      IndexSpace rh_space = runtime->get_index_subspace(ctx, rhs, rh_color);

      // Ensure the color exists.
      lh_coloring[rh_color];

      for (IndexIterator lh_it(runtime, ctx, lh_space); lh_it.has_next();) {
        size_t lh_count = 0;
        ptr_t lh_ptr = lh_it.next_span(lh_count);
        ptr_t lh_end = lh_ptr.value + lh_count - 1;

        for (IndexIterator rh_it(runtime, ctx, rh_space, lh_ptr); rh_it.has_next();) {
          size_t rh_count = 0;
          ptr_t rh_ptr = rh_it.next_span(rh_count);
          ptr_t rh_end = rh_ptr.value + rh_count - 1;
          if (rh_ptr.value > lh_end.value) {
            break;
          }

          if (rh_end.value > lh_end.value) {
            lh_coloring[rh_color].ranges.insert(std::pair<ptr_t, ptr_t>(rh_ptr, lh_end));
            break;
          }

          lh_coloring[rh_color].ranges.insert(std::pair<ptr_t, ptr_t>(rh_ptr, rh_end));
        }
      }
    }

    runtime->create_index_partition(
      ctx, lh_space, lh_coloring,
      runtime->is_index_partition_disjoint(ctx, rhs),
      rhs_color);
  }
#endif
}
static void
create_cross_product_multi(HighLevelRuntime *runtime,
                           Context ctx,
                           size_t npartitions,
                           IndexPartition next,
                           std::vector<IndexPartition>::iterator rest,
                           std::vector<IndexPartition>::iterator end,
                           int level)
{
  if (rest != end) {
    create_cross_product(runtime, ctx, next, *rest);
    Domain colors = runtime->get_index_partition_color_space(ctx, next);
    Color color2 = runtime->get_index_partition_color(ctx, *rest);
    for (Domain::DomainPointIterator dp(colors); dp; dp++) {
      Color color = dp.p.get_point<1>()[0];
      IndexSpace is = runtime->get_index_subspace(ctx, next, color);
      IndexPartition ip = runtime->get_index_partition(ctx, is, color2);
      create_cross_product_multi(runtime, ctx, npartitions - 1, ip, rest+1, end, level + 1);
    }
  }
}

legion_terra_index_cross_product_t
legion_terra_index_cross_product_create(legion_runtime_t runtime_,
                                        legion_context_t ctx_,
                                        legion_index_partition_t lhs_,
                                        legion_index_partition_t rhs_)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();
  IndexPartition lhs = CObjectWrapper::unwrap(lhs_);
  IndexPartition rhs = CObjectWrapper::unwrap(rhs_);

  create_cross_product(runtime, ctx, lhs, rhs);

  legion_terra_index_cross_product_t result;
  result.partition = CObjectWrapper::wrap(lhs);
  result.other = CObjectWrapper::wrap(rhs);
  return result;
}

legion_terra_index_cross_product_t
legion_terra_index_cross_product_create_multi(
  legion_runtime_t runtime_,
  legion_context_t ctx_,
  legion_index_partition_t *partitions_,
  size_t npartitions)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();

  std::vector<IndexPartition> partitions;
  for (size_t i = 0; i < npartitions; i++) {
    partitions.push_back(CObjectWrapper::unwrap(partitions_[i]));
  }

  assert(npartitions >= 2);
  create_cross_product_multi(runtime, ctx, npartitions,
                             partitions[0],
                             partitions.begin() + 1, partitions.end(), 0);

  legion_terra_index_cross_product_t result;
  result.partition = CObjectWrapper::wrap(partitions[0]);
  result.other = CObjectWrapper::wrap(partitions[1]);
  return result;
}

legion_index_partition_t
legion_terra_index_cross_product_get_partition(
  legion_terra_index_cross_product_t prod)
{
  return prod.partition;
}

legion_index_partition_t
legion_terra_index_cross_product_get_subpartition_by_color(
  legion_runtime_t runtime_,
  legion_context_t ctx_,
  legion_terra_index_cross_product_t prod,
  legion_color_t color)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();
  IndexPartition partition = CObjectWrapper::unwrap(prod.partition);
  IndexPartition other = CObjectWrapper::unwrap(prod.other);

  IndexSpace is = runtime->get_index_subspace(ctx, partition, color);
  IndexPartition ip = runtime->get_index_partition(
    ctx, is, runtime->get_index_partition_color(ctx, other));
  return CObjectWrapper::wrap(ip);
}

legion_terra_cached_index_iterator_t
legion_terra_cached_index_iterator_create(
  legion_runtime_t runtime_,
  legion_context_t ctx_,
  legion_index_space_t handle_)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();
  IndexSpace handle = CObjectWrapper::unwrap(handle_);

  CachedIndexIterator *result = new CachedIndexIterator(runtime, ctx, handle, true);
  return TerraCObjectWrapper::wrap(result);
}

void
legion_terra_cached_index_iterator_destroy(
  legion_terra_cached_index_iterator_t handle_)
{
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  delete handle;
}

bool
legion_terra_cached_index_iterator_has_next(
  legion_terra_cached_index_iterator_t handle_)
{
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  return handle->has_next();
}

legion_ptr_t
legion_terra_cached_index_iterator_next_span(
  legion_terra_cached_index_iterator_t handle_,
  size_t *count,
  size_t req_count /* must be -1 */)
{
  assert(req_count == size_t(-1));
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  ptr_t result = handle->next_span(count);
  return CObjectWrapper::wrap(result);
}

void
legion_terra_cached_index_iterator_reset(
  legion_terra_cached_index_iterator_t handle_)
{
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  handle->reset();
}

unsigned
legion_terra_task_launcher_get_region_requirement_logical_region(
  legion_task_launcher_t launcher_,
  legion_logical_region_t region_)
{
  TaskLauncher *launcher = CObjectWrapper::unwrap(launcher_);
  LogicalRegion region = CObjectWrapper::unwrap(region_);

  unsigned idx = (unsigned)-1;
  for (unsigned i = 0; i < launcher->region_requirements.size(); i++) {
    if (launcher->region_requirements[i].handle_type == SINGULAR &&
        launcher->region_requirements[i].region == region) {
      idx = i;
      break;
    }
  }
  return idx;
}

bool
legion_terra_task_launcher_has_field(
  legion_task_launcher_t launcher_,
  unsigned idx,
  legion_field_id_t fid)
{
  TaskLauncher *launcher = CObjectWrapper::unwrap(launcher_);
  const RegionRequirement &req = launcher->region_requirements[idx];
  return req.privilege_fields.count(fid) > 0;
}
<commit_msg>bindings: Some heuristics to determine which way to run the cross-product.<commit_after>/* Copyright 2016 Stanford University, NVIDIA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "legion_terra_partitions.h"
#include "legion_terra_partitions_cxx.h"

#include "arrays.h"
#include "legion.h"
#include "legion_c_util.h"
#include "legion_utilities.h"
#include "lowlevel.h"
#include "utilities.h"

#ifdef SHARED_LOWLEVEL
#define USE_LEGION_CROSS_PRODUCT 1
#else
// General LLR can't handle new partion API yet.
#define USE_LEGION_CROSS_PRODUCT 0
#endif

#ifndef USE_TLS
// Mac OS X and GCC <= 4.7 do not support C++11 thread_local.
#if __cplusplus < 201103L || defined(__MACH__) || (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)))
#define USE_TLS 0
#else
#define USE_TLS 1
#endif
#endif

struct CachedIndexIterator {
public:
  CachedIndexIterator(HighLevelRuntime *rt, Context ctx, IndexSpace is, bool gl)
    : runtime(rt), context(ctx), space(is), index(0), cached(false), global(gl)
  {
  }

  bool has_next() {
    if (!cached) cache();
    return index < spans.size();
  }

  ptr_t next_span(size_t *count) {
    if (!cached) cache();
    if (index >= spans.size()) {
      *count = 0;
      return ptr_t::nil();
    }
    std::pair<ptr_t, size_t> span = spans[index++];
    *count = span.second;
    return span.first;
  }

  void reset() {
    index = 0;
  }

private:
  void cache() {
    assert(!cached);

    if (global) {
#if !USE_TLS
      LegionRuntime::HighLevel::AutoLock guard(global_lock);
#endif
      std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > >::iterator it =
        global_cache.find(space);
      if (it != global_cache.end()) {
        spans = it->second;
        cached = true;
        return;
      }
    }

    IndexIterator it(runtime, context, space);
    while (it.has_next()) {
      size_t count = 0;
      ptr_t start = it.next_span(count);
      assert(count && !start.is_null());
      spans.push_back(std::pair<ptr_t, size_t>(start, count));
    }

    if (global) {
#if USE_TLS
      global_cache[space] = spans;
#else
      LegionRuntime::HighLevel::AutoLock guard(global_lock);
      if (!global_cache.count(space)) {
        global_cache[space] = spans;
      }
#endif
    }

    cached = true;
  }

private:
  HighLevelRuntime *runtime;
  Context context;
  IndexSpace space;
  std::vector<std::pair<ptr_t, size_t> > spans;
  size_t index;
  bool cached;
  bool global;
private:
#if USE_TLS
  static thread_local
  std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > > global_cache;
#else
  static std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > > global_cache;
  static ImmovableLock global_lock;
#endif
};

#if USE_TLS
thread_local std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > >
  CachedIndexIterator::global_cache;
#else
std::map<IndexSpace, std::vector<std::pair<ptr_t, size_t> > >
  CachedIndexIterator::global_cache;
ImmovableLock CachedIndexIterator::global_lock(true);
#endif

class TerraCObjectWrapper {
public:

#define NEW_OPAQUE_WRAPPER(T_, T)                                       \
      static T_ wrap(T t) {                                             \
        T_ t_;                                                          \
        t_.impl = static_cast<void *>(t);                               \
        return t_;                                                      \
      }                                                                 \
      static const T_ wrap_const(const T t) {                           \
        T_ t_;                                                          \
        t_.impl = const_cast<void *>(static_cast<const void *>(t));     \
        return t_;                                                      \
      }                                                                 \
      static T unwrap(T_ t_) {                                          \
        return static_cast<T>(t_.impl);                                 \
      }                                                                 \
      static const T unwrap_const(const T_ t_) {                        \
        return static_cast<const T>(t_.impl);                           \
      }

  NEW_OPAQUE_WRAPPER(legion_terra_cached_index_iterator_t, CachedIndexIterator *);
#undef NEW_OPAQUE_WRAPPER
};

#if !USE_LEGION_CROSS_PRODUCT
static void
create_cross_product_coloring(HighLevelRuntime *runtime,
                              Context ctx,
                              IndexPartition lhs,
                              IndexPartition rhs,
                              std::map<Color, Coloring> &coloring)
{
  Domain lhs_colors = runtime->get_index_partition_color_space(ctx, lhs);
  Domain rhs_colors = runtime->get_index_partition_color_space(ctx, rhs);

  for (Domain::DomainPointIterator lh_dp(lhs_colors); lh_dp; lh_dp++) {
    Color lh_color = lh_dp.p.get_point<1>()[0];
    IndexSpace lh_space = runtime->get_index_subspace(ctx, lhs, lh_color);

    for (Domain::DomainPointIterator rh_dp(rhs_colors); rh_dp; rh_dp++) {
      Color rh_color = rh_dp.p.get_point<1>()[0];
      IndexSpace rh_space = runtime->get_index_subspace(ctx, rhs, rh_color);

      for (IndexIterator lh_it(runtime, ctx, lh_space); lh_it.has_next();) {
        size_t lh_count = 0;
        ptr_t lh_ptr = lh_it.next_span(lh_count);
        ptr_t lh_end = lh_ptr.value + lh_count - 1;

        for (IndexIterator rh_it(runtime, ctx, rh_space, lh_ptr); rh_it.has_next();) {
          size_t rh_count = 0;
          ptr_t rh_ptr = rh_it.next_span(rh_count);
          ptr_t rh_end = rh_ptr.value + rh_count - 1;
          if (rh_ptr.value > lh_end.value) {
            break;
          }

          if (rh_end.value > lh_end.value) {
            coloring[lh_color][rh_color].ranges.insert(std::pair<ptr_t, ptr_t>(rh_ptr, lh_end));
            break;
          }

          coloring[lh_color][rh_color].ranges.insert(std::pair<ptr_t, ptr_t>(rh_ptr, rh_end));
        }
      }
    }
  }
}
#endif

void
create_cross_product(HighLevelRuntime *runtime,
                     Context ctx,
                     IndexPartition lhs,
                     IndexPartition rhs,
                     Color rhs_color /* = -1 */)
{
  if (rhs_color == (Color)-1) {
    rhs_color = runtime->get_index_partition_color(ctx, rhs);
  }

#if USE_LEGION_CROSS_PRODUCT
  std::map<DomainPoint, IndexPartition> handles;
  runtime->create_cross_product_partitions(
    ctx, lhs, rhs, handles,
    (runtime->is_index_partition_disjoint(ctx, rhs) ? DISJOINT_KIND : ALIASED_KIND),
    rhs_color, true);
#else
  // FIXME: Validate: same index tree

  Domain lhs_colors = runtime->get_index_partition_color_space(ctx, lhs);
  Domain rhs_colors = runtime->get_index_partition_color_space(ctx, rhs);

  // The efficiency of this algorithm depends heavily on how many
  // spans are in lhs and rhs. Since it is *MUCH* better to have a
  // smaller number of spans on lhs, it is worth spending a little
  // time here estimating which will have fewer spans.

  bool flip = false;
  for (Domain::DomainPointIterator lh_dp(lhs_colors), rh_dp(rhs_colors); lh_dp && rh_dp;) {
    Color lh_color = lh_dp.p.get_point<1>()[0];
    IndexSpace lh_space = runtime->get_index_subspace(ctx, lhs, lh_color);
    Color rh_color = rh_dp.p.get_point<1>()[0];
    IndexSpace rh_space = runtime->get_index_subspace(ctx, rhs, rh_color);

    IndexIterator lh_it(runtime, ctx, lh_space);
    IndexIterator rh_it(runtime, ctx, rh_space);
    for (; lh_it.has_next() && rh_it.has_next();) {
      size_t lh_count = 0;
      lh_it.next_span(lh_count);
      size_t rh_count = 0;
      rh_it.next_span(rh_count);
    }

    flip = lh_it.has_next() && !rh_it.has_next();
    break;
  }

  std::map<Color, Coloring> coloring;
  if (flip) {
    create_cross_product_coloring(runtime, ctx, rhs, lhs, coloring);
  } else {
    create_cross_product_coloring(runtime, ctx, lhs, rhs, coloring);
  }

  for (Domain::DomainPointIterator lh_dp(lhs_colors); lh_dp; lh_dp++) {
    Color lh_color = lh_dp.p.get_point<1>()[0];
    IndexSpace lh_space = runtime->get_index_subspace(ctx, lhs, lh_color);

    Coloring empty; // Make sure this stays on the stack while we need it...
    Coloring &lh_coloring = flip ? empty : coloring[lh_color];
    for (Domain::DomainPointIterator rh_dp(rhs_colors); rh_dp; rh_dp++) {
      Color rh_color = rh_dp.p.get_point<1>()[0];

      // Flip order of coloring.
      if (flip) {
        lh_coloring[rh_color] = coloring[rh_color][lh_color];
      }

      // Ensure the color exists.
      lh_coloring[rh_color];
    }

    runtime->create_index_partition(
      ctx, lh_space, lh_coloring,
      runtime->is_index_partition_disjoint(ctx, rhs),
      rhs_color);
  }
#endif
}
static void
create_cross_product_multi(HighLevelRuntime *runtime,
                           Context ctx,
                           size_t npartitions,
                           IndexPartition next,
                           std::vector<IndexPartition>::iterator rest,
                           std::vector<IndexPartition>::iterator end,
                           int level)
{
  if (rest != end) {
    create_cross_product(runtime, ctx, next, *rest);
    Domain colors = runtime->get_index_partition_color_space(ctx, next);
    Color color2 = runtime->get_index_partition_color(ctx, *rest);
    for (Domain::DomainPointIterator dp(colors); dp; dp++) {
      Color color = dp.p.get_point<1>()[0];
      IndexSpace is = runtime->get_index_subspace(ctx, next, color);
      IndexPartition ip = runtime->get_index_partition(ctx, is, color2);
      create_cross_product_multi(runtime, ctx, npartitions - 1, ip, rest+1, end, level + 1);
    }
  }
}

legion_terra_index_cross_product_t
legion_terra_index_cross_product_create(legion_runtime_t runtime_,
                                        legion_context_t ctx_,
                                        legion_index_partition_t lhs_,
                                        legion_index_partition_t rhs_)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();
  IndexPartition lhs = CObjectWrapper::unwrap(lhs_);
  IndexPartition rhs = CObjectWrapper::unwrap(rhs_);

  create_cross_product(runtime, ctx, lhs, rhs);

  legion_terra_index_cross_product_t result;
  result.partition = CObjectWrapper::wrap(lhs);
  result.other = CObjectWrapper::wrap(rhs);
  return result;
}

legion_terra_index_cross_product_t
legion_terra_index_cross_product_create_multi(
  legion_runtime_t runtime_,
  legion_context_t ctx_,
  legion_index_partition_t *partitions_,
  size_t npartitions)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();

  std::vector<IndexPartition> partitions;
  for (size_t i = 0; i < npartitions; i++) {
    partitions.push_back(CObjectWrapper::unwrap(partitions_[i]));
  }

  assert(npartitions >= 2);
  create_cross_product_multi(runtime, ctx, npartitions,
                             partitions[0],
                             partitions.begin() + 1, partitions.end(), 0);

  legion_terra_index_cross_product_t result;
  result.partition = CObjectWrapper::wrap(partitions[0]);
  result.other = CObjectWrapper::wrap(partitions[1]);
  return result;
}

legion_index_partition_t
legion_terra_index_cross_product_get_partition(
  legion_terra_index_cross_product_t prod)
{
  return prod.partition;
}

legion_index_partition_t
legion_terra_index_cross_product_get_subpartition_by_color(
  legion_runtime_t runtime_,
  legion_context_t ctx_,
  legion_terra_index_cross_product_t prod,
  legion_color_t color)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();
  IndexPartition partition = CObjectWrapper::unwrap(prod.partition);
  IndexPartition other = CObjectWrapper::unwrap(prod.other);

  IndexSpace is = runtime->get_index_subspace(ctx, partition, color);
  IndexPartition ip = runtime->get_index_partition(
    ctx, is, runtime->get_index_partition_color(ctx, other));
  return CObjectWrapper::wrap(ip);
}

legion_terra_cached_index_iterator_t
legion_terra_cached_index_iterator_create(
  legion_runtime_t runtime_,
  legion_context_t ctx_,
  legion_index_space_t handle_)
{
  HighLevelRuntime *runtime = CObjectWrapper::unwrap(runtime_);
  Context ctx = CObjectWrapper::unwrap(ctx_)->context();
  IndexSpace handle = CObjectWrapper::unwrap(handle_);

  CachedIndexIterator *result = new CachedIndexIterator(runtime, ctx, handle, true);
  return TerraCObjectWrapper::wrap(result);
}

void
legion_terra_cached_index_iterator_destroy(
  legion_terra_cached_index_iterator_t handle_)
{
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  delete handle;
}

bool
legion_terra_cached_index_iterator_has_next(
  legion_terra_cached_index_iterator_t handle_)
{
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  return handle->has_next();
}

legion_ptr_t
legion_terra_cached_index_iterator_next_span(
  legion_terra_cached_index_iterator_t handle_,
  size_t *count,
  size_t req_count /* must be -1 */)
{
  assert(req_count == size_t(-1));
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  ptr_t result = handle->next_span(count);
  return CObjectWrapper::wrap(result);
}

void
legion_terra_cached_index_iterator_reset(
  legion_terra_cached_index_iterator_t handle_)
{
  CachedIndexIterator *handle = TerraCObjectWrapper::unwrap(handle_);

  handle->reset();
}

unsigned
legion_terra_task_launcher_get_region_requirement_logical_region(
  legion_task_launcher_t launcher_,
  legion_logical_region_t region_)
{
  TaskLauncher *launcher = CObjectWrapper::unwrap(launcher_);
  LogicalRegion region = CObjectWrapper::unwrap(region_);

  unsigned idx = (unsigned)-1;
  for (unsigned i = 0; i < launcher->region_requirements.size(); i++) {
    if (launcher->region_requirements[i].handle_type == SINGULAR &&
        launcher->region_requirements[i].region == region) {
      idx = i;
      break;
    }
  }
  return idx;
}

bool
legion_terra_task_launcher_has_field(
  legion_task_launcher_t launcher_,
  unsigned idx,
  legion_field_id_t fid)
{
  TaskLauncher *launcher = CObjectWrapper::unwrap(launcher_);
  const RegionRequirement &req = launcher->region_requirements[idx];
  return req.privilege_fields.count(fid) > 0;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string>
#include "v8.h"
#include "libplatform/libplatform.h"
#include "binding.h"

using namespace v8;

struct worker_s {
  int x;
  void* data;
  worker_recv_cb cb;
  Isolate* isolate;
  std::string last_exception;
  Persistent<Function> recv;
  Persistent<Context> context;
};

// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}

// Exception details will be appended to the first argument.
std::string ExceptionString(Isolate* isolate, TryCatch* try_catch) {
  std::string out;
  size_t scratchSize = 100;
  char scratch[scratchSize]; // just some scratch space for sprintf

  HandleScope handle_scope(isolate);
  String::Utf8Value exception(try_catch->Exception());
  const char* exception_string = ToCString(exception);

  printf("exception string: %s\n", exception_string);

  Handle<Message> message = try_catch->Message();

  if (message.IsEmpty()) {
    // V8 didn't provide any extra information about this error; just
    // print the exception.
    out.append(exception_string);
    out.append("\n");
  } else {
    // Print (filename):(line number): (message).
    String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
    const char* filename_string = ToCString(filename);
    int linenum = message->GetLineNumber();

    snprintf(scratch, scratchSize, "%s:%i: %s\n", filename_string, linenum, exception_string);
    out.append(scratch);

    // Print line of source code.
    String::Utf8Value sourceline(message->GetSourceLine());
    const char* sourceline_string = ToCString(sourceline);

    out.append(sourceline_string);
    out.append("\n");

    // Print wavy underline (GetUnderline is deprecated).
    int start = message->GetStartColumn();
    for (int i = 0; i < start; i++) {
      out.append(" ");
    }
    int end = message->GetEndColumn();
    for (int i = start; i < end; i++) {
      out.append("^");
    }
    out.append("\n");
    String::Utf8Value stack_trace(try_catch->StackTrace());
    if (stack_trace.length() > 0) {
      const char* stack_trace_string = ToCString(stack_trace);
      out.append(stack_trace_string);
      out.append("\n");
    }
  }
  return out;
}

extern "C" {
#include "_cgo_export.h"

void go_recv_cb(const char* msg, void* data) {
  recvCb((char*)msg, data);
}

const char* worker_version() {
  return V8::GetVersion();
}

const char* worker_last_exception(worker* w) {
  return w->last_exception.c_str();
}

int worker_load(worker* w, char* name_s, char* source_s) {
  Locker locker(w->isolate);
  Isolate::Scope isolate_scope(w->isolate);
  HandleScope handle_scope(w->isolate);

  Local<Context> context = Local<Context>::New(w->isolate, w->context);
  Context::Scope context_scope(context);

  TryCatch try_catch;

  Local<String> name = String::NewFromUtf8(w->isolate, name_s);
  Local<String> source = String::NewFromUtf8(w->isolate, source_s);

  ScriptOrigin origin(name);

  Local<Script> script = Script::Compile(source, &origin);

  if (script.IsEmpty()) {
    assert(try_catch.HasCaught());
    w->last_exception = ExceptionString(w->isolate, &try_catch);
    return 1;
  }

  Handle<Value> result = script->Run();

  if (result.IsEmpty()) {
    assert(try_catch.HasCaught());
    w->last_exception = ExceptionString(w->isolate, &try_catch);
    return 2;
  }

  return 0;
}

void Print(const FunctionCallbackInfo<Value>& args) {
  bool first = true;
  for (int i = 0; i < args.Length(); i++) {
    HandleScope handle_scope(args.GetIsolate());
    if (first) {
      first = false;
    } else {
      printf(" ");
    }
    String::Utf8Value str(args[i]);
    const char* cstr = ToCString(str);
    printf("%s", cstr);
  }
  printf("\n");
  fflush(stdout);
}

// sets the recv callback.
void Recv(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  worker* w = (worker*)isolate->GetData(0);
  assert(w->isolate == isolate);

  HandleScope handle_scope(isolate);

  Local<Context> context = Local<Context>::New(w->isolate, w->context);
  Context::Scope context_scope(context);

  Local<Value> v = args[0];
  assert(v->IsFunction());
  Local<Function> func = Local<Function>::Cast(v);

  w->recv.Reset(isolate, func);
}

// Called from javascript. Must route message to golang.
void Send(const FunctionCallbackInfo<Value>& args) {
  std::string msg;
  worker* w = NULL;
  {
    Isolate* isolate = args.GetIsolate();
    w = static_cast<worker*>(isolate->GetData(0));
    assert(w->isolate == isolate);

    Locker locker(w->isolate);
    HandleScope handle_scope(isolate);

    Local<Context> context = Local<Context>::New(w->isolate, w->context);
    Context::Scope context_scope(context);

    Local<Value> v = args[0];
    assert(v->IsString());

    String::Utf8Value str(v);
    msg = ToCString(str);
  }

  // XXX should we use Unlocker?
  w->cb(msg.c_str(), w->data);
}

// Called from golang. Must route message to javascript lang.
// non-zero return value indicates error. check worker_last_exception().
int worker_send(worker* w, const char* msg) {
  Locker locker(w->isolate);
  Isolate::Scope isolate_scope(w->isolate);
  HandleScope handle_scope(w->isolate);

  Local<Context> context = Local<Context>::New(w->isolate, w->context);
  Context::Scope context_scope(context);

  TryCatch try_catch;

  Local<Function> recv = Local<Function>::New(w->isolate, w->recv);
  if (recv.IsEmpty()) {
    w->last_exception = "$recv not called";
    return 1;
  }

  Local<Value> args[1];
  args[0] = String::NewFromUtf8(w->isolate, msg);

  assert(!try_catch.HasCaught());

  recv->Call(context->Global(), 1, args);

  if (try_catch.HasCaught()) {
    w->last_exception = ExceptionString(w->isolate, &try_catch);
    return 2;
  }

  return 0;
}

void v8_init() {
  V8::Initialize();

  Platform* platform = platform::CreateDefaultPlatform();
  V8::InitializePlatform(platform);
}

worker* worker_new(worker_recv_cb cb, void* data) {
  Isolate* isolate = Isolate::New();
  Locker locker(isolate);
  Isolate::Scope isolate_scope(isolate);
  HandleScope handle_scope(isolate);

  worker* w = new(worker);
  w->isolate = isolate;
	w->isolate->SetCaptureStackTraceForUncaughtExceptions(true);
  w->isolate->SetData(0, w);
  w->data = data;
  w->cb = cb;

  Local<ObjectTemplate> global = ObjectTemplate::New(w->isolate);

  global->Set(String::NewFromUtf8(w->isolate, "$print"),
              FunctionTemplate::New(w->isolate, Print));

  global->Set(String::NewFromUtf8(w->isolate, "$recv"),
              FunctionTemplate::New(w->isolate, Recv));

  global->Set(String::NewFromUtf8(w->isolate, "$send"),
              FunctionTemplate::New(w->isolate, Send));

  Local<Context> context = Context::New(w->isolate, NULL, global);
  w->context.Reset(w->isolate, context);
  //context->Enter();

  return w;
}

}
<commit_msg>add ArrayBuffer::Allocator<commit_after>#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string>
#include "v8.h"
#include "libplatform/libplatform.h"
#include "binding.h"

using namespace v8;

struct worker_s {
  int x;
  void* data;
  worker_recv_cb cb;
  Isolate* isolate;
  std::string last_exception;
  Persistent<Function> recv;
  Persistent<Context> context;
};

// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}

class ArrayBufferAllocator : public ArrayBuffer::Allocator {
 public:
  virtual void* Allocate(size_t length) {
    void* data = AllocateUninitialized(length);
    return data == NULL ? data : memset(data, 0, length);
  }
  virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
  virtual void Free(void* data, size_t) { free(data); }
};

// Exception details will be appended to the first argument.
std::string ExceptionString(Isolate* isolate, TryCatch* try_catch) {
  std::string out;
  size_t scratchSize = 100;
  char scratch[scratchSize]; // just some scratch space for sprintf

  HandleScope handle_scope(isolate);
  String::Utf8Value exception(try_catch->Exception());
  const char* exception_string = ToCString(exception);

  printf("exception string: %s\n", exception_string);

  Handle<Message> message = try_catch->Message();

  if (message.IsEmpty()) {
    // V8 didn't provide any extra information about this error; just
    // print the exception.
    out.append(exception_string);
    out.append("\n");
  } else {
    // Print (filename):(line number): (message).
    String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
    const char* filename_string = ToCString(filename);
    int linenum = message->GetLineNumber();

    snprintf(scratch, scratchSize, "%s:%i: %s\n", filename_string, linenum, exception_string);
    out.append(scratch);

    // Print line of source code.
    String::Utf8Value sourceline(message->GetSourceLine());
    const char* sourceline_string = ToCString(sourceline);

    out.append(sourceline_string);
    out.append("\n");

    // Print wavy underline (GetUnderline is deprecated).
    int start = message->GetStartColumn();
    for (int i = 0; i < start; i++) {
      out.append(" ");
    }
    int end = message->GetEndColumn();
    for (int i = start; i < end; i++) {
      out.append("^");
    }
    out.append("\n");
    String::Utf8Value stack_trace(try_catch->StackTrace());
    if (stack_trace.length() > 0) {
      const char* stack_trace_string = ToCString(stack_trace);
      out.append(stack_trace_string);
      out.append("\n");
    }
  }
  return out;
}

extern "C" {
#include "_cgo_export.h"

void go_recv_cb(const char* msg, void* data) {
  recvCb((char*)msg, data);
}

const char* worker_version() {
  return V8::GetVersion();
}

const char* worker_last_exception(worker* w) {
  return w->last_exception.c_str();
}

int worker_load(worker* w, char* name_s, char* source_s) {
  Locker locker(w->isolate);
  Isolate::Scope isolate_scope(w->isolate);
  HandleScope handle_scope(w->isolate);

  Local<Context> context = Local<Context>::New(w->isolate, w->context);
  Context::Scope context_scope(context);

  TryCatch try_catch;

  Local<String> name = String::NewFromUtf8(w->isolate, name_s);
  Local<String> source = String::NewFromUtf8(w->isolate, source_s);

  ScriptOrigin origin(name);

  Local<Script> script = Script::Compile(source, &origin);

  if (script.IsEmpty()) {
    assert(try_catch.HasCaught());
    w->last_exception = ExceptionString(w->isolate, &try_catch);
    return 1;
  }

  Handle<Value> result = script->Run();

  if (result.IsEmpty()) {
    assert(try_catch.HasCaught());
    w->last_exception = ExceptionString(w->isolate, &try_catch);
    return 2;
  }

  return 0;
}

void Print(const FunctionCallbackInfo<Value>& args) {
  bool first = true;
  for (int i = 0; i < args.Length(); i++) {
    HandleScope handle_scope(args.GetIsolate());
    if (first) {
      first = false;
    } else {
      printf(" ");
    }
    String::Utf8Value str(args[i]);
    const char* cstr = ToCString(str);
    printf("%s", cstr);
  }
  printf("\n");
  fflush(stdout);
}

// sets the recv callback.
void Recv(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  worker* w = (worker*)isolate->GetData(0);
  assert(w->isolate == isolate);

  HandleScope handle_scope(isolate);

  Local<Context> context = Local<Context>::New(w->isolate, w->context);
  Context::Scope context_scope(context);

  Local<Value> v = args[0];
  assert(v->IsFunction());
  Local<Function> func = Local<Function>::Cast(v);

  w->recv.Reset(isolate, func);
}

// Called from javascript. Must route message to golang.
void Send(const FunctionCallbackInfo<Value>& args) {
  std::string msg;
  worker* w = NULL;
  {
    Isolate* isolate = args.GetIsolate();
    w = static_cast<worker*>(isolate->GetData(0));
    assert(w->isolate == isolate);

    Locker locker(w->isolate);
    HandleScope handle_scope(isolate);

    Local<Context> context = Local<Context>::New(w->isolate, w->context);
    Context::Scope context_scope(context);

    Local<Value> v = args[0];
    assert(v->IsString());

    String::Utf8Value str(v);
    msg = ToCString(str);
  }

  // XXX should we use Unlocker?
  w->cb(msg.c_str(), w->data);
}

// Called from golang. Must route message to javascript lang.
// non-zero return value indicates error. check worker_last_exception().
int worker_send(worker* w, const char* msg) {
  Locker locker(w->isolate);
  Isolate::Scope isolate_scope(w->isolate);
  HandleScope handle_scope(w->isolate);

  Local<Context> context = Local<Context>::New(w->isolate, w->context);
  Context::Scope context_scope(context);

  TryCatch try_catch;

  Local<Function> recv = Local<Function>::New(w->isolate, w->recv);
  if (recv.IsEmpty()) {
    w->last_exception = "$recv not called";
    return 1;
  }

  Local<Value> args[1];
  args[0] = String::NewFromUtf8(w->isolate, msg);

  assert(!try_catch.HasCaught());

  recv->Call(context->Global(), 1, args);

  if (try_catch.HasCaught()) {
    w->last_exception = ExceptionString(w->isolate, &try_catch);
    return 2;
  }

  return 0;
}

static ArrayBufferAllocator array_buffer_allocator;

void v8_init() {
  V8::Initialize();

  Platform* platform = platform::CreateDefaultPlatform();
  V8::InitializePlatform(platform);

  V8::SetArrayBufferAllocator(&array_buffer_allocator);
}

worker* worker_new(worker_recv_cb cb, void* data) {
  Isolate* isolate = Isolate::New();
  Locker locker(isolate);
  Isolate::Scope isolate_scope(isolate);
  HandleScope handle_scope(isolate);

  worker* w = new(worker);
  w->isolate = isolate;
	w->isolate->SetCaptureStackTraceForUncaughtExceptions(true);
  w->isolate->SetData(0, w);
  w->data = data;
  w->cb = cb;

  Local<ObjectTemplate> global = ObjectTemplate::New(w->isolate);

  global->Set(String::NewFromUtf8(w->isolate, "$print"),
              FunctionTemplate::New(w->isolate, Print));

  global->Set(String::NewFromUtf8(w->isolate, "$recv"),
              FunctionTemplate::New(w->isolate, Recv));

  global->Set(String::NewFromUtf8(w->isolate, "$send"),
              FunctionTemplate::New(w->isolate, Send));

  Local<Context> context = Context::New(w->isolate, NULL, global);
  w->context.Reset(w->isolate, context);
  //context->Enter();

  return w;
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/drive/file_task_executor.h"

#include <string>
#include <vector>

#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/drive_integration_service.h"
#include "chrome/browser/chromeos/drive/file_system_interface.h"
#include "chrome/browser/drive/drive_service_interface.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "content/public/browser/browser_thread.h"
#include "webkit/browser/fileapi/file_system_url.h"

using fileapi::FileSystemURL;

namespace drive {

FileTaskExecutor::FileTaskExecutor(Profile* profile,
                                   const std::string& app_id)
  : profile_(profile),
    app_id_(app_id),
    current_index_(0),
    weak_ptr_factory_(this) {
}

FileTaskExecutor::~FileTaskExecutor() {
}

void FileTaskExecutor::Execute(
    const std::vector<FileSystemURL>& file_urls,
    const file_manager::file_tasks::FileTaskFinishedCallback& done) {
  done_ = done;

  std::vector<base::FilePath> paths;
  for (size_t i = 0; i < file_urls.size(); ++i) {
    base::FilePath path = util::ExtractDrivePathFromFileSystemUrl(file_urls[i]);
    if (path.empty()) {
      Done(false);
      return;
    }
    paths.push_back(path);
  }

  FileSystemInterface* file_system = util::GetFileSystemByProfile(profile_);
  if (!file_system) {
    Done(false);
    return;
  }

  // Reset the index, so we know when we're done.
  DCHECK_EQ(current_index_, 0);
  current_index_ = paths.size();

  for (size_t i = 0; i < paths.size(); ++i) {
    file_system->GetResourceEntry(
        paths[i],
        base::Bind(&FileTaskExecutor::OnFileEntryFetched,
                   weak_ptr_factory_.GetWeakPtr()));
  }
}

void FileTaskExecutor::OnFileEntryFetched(FileError error,
                                          scoped_ptr<ResourceEntry> entry) {
  // Here, we are only interested in files.
  if (entry.get() && !entry->has_file_specific_info())
    error = FILE_ERROR_NOT_FOUND;

  DriveServiceInterface* drive_service =
      util::GetDriveServiceByProfile(profile_);

  if (!drive_service || error != FILE_ERROR_OK) {
    Done(false);
    return;
  }

  // Send off a request for the drive service to authorize the apps for the
  // current document entry for this document so we can get the
  // open-with-<app_id> urls from the document entry.
  drive_service->AuthorizeApp(entry->resource_id(),
                              app_id_,
                              base::Bind(&FileTaskExecutor::OnAppAuthorized,
                                         weak_ptr_factory_.GetWeakPtr(),
                                         entry->resource_id()));
}

void FileTaskExecutor::OnAppAuthorized(const std::string& resource_id,
                                       google_apis::GDataErrorCode error,
                                       const GURL& open_link) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  DriveIntegrationService* service =
      DriveIntegrationServiceFactory::FindForProfile(profile_);
  if (!service || !service->IsMounted() ||
      error != google_apis::HTTP_SUCCESS || open_link.is_empty()) {
    Done(false);
    return;
  }

  {
    chrome::ScopedTabbedBrowserDisplayer displayer(
         profile_, chrome::HOST_DESKTOP_TYPE_ASH);
    chrome::AddSelectedTabWithURL(displayer.browser(), open_link,
                                  content::PAGE_TRANSITION_LINK);
  }

  // We're done with this file.  If this is the last one, then we're done.
  current_index_--;
  DCHECK_GE(current_index_, 0);
  if (current_index_ == 0)
    Done(true);
}

void FileTaskExecutor::Done(bool success) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  if (!done_.is_null())
    done_.Run(success);
  delete this;
}

}  // namespace drive
<commit_msg>Files.app: Open drive apps in the current desktop.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/drive/file_task_executor.h"

#include <string>
#include <vector>

#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/drive_integration_service.h"
#include "chrome/browser/chromeos/drive/file_system_interface.h"
#include "chrome/browser/drive/drive_service_interface.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "content/public/browser/browser_thread.h"
#include "webkit/browser/fileapi/file_system_url.h"

using fileapi::FileSystemURL;

namespace drive {

FileTaskExecutor::FileTaskExecutor(Profile* profile,
                                   const std::string& app_id)
  : profile_(profile),
    app_id_(app_id),
    current_index_(0),
    weak_ptr_factory_(this) {
}

FileTaskExecutor::~FileTaskExecutor() {
}

void FileTaskExecutor::Execute(
    const std::vector<FileSystemURL>& file_urls,
    const file_manager::file_tasks::FileTaskFinishedCallback& done) {
  done_ = done;

  std::vector<base::FilePath> paths;
  for (size_t i = 0; i < file_urls.size(); ++i) {
    base::FilePath path = util::ExtractDrivePathFromFileSystemUrl(file_urls[i]);
    if (path.empty()) {
      Done(false);
      return;
    }
    paths.push_back(path);
  }

  FileSystemInterface* file_system = util::GetFileSystemByProfile(profile_);
  if (!file_system) {
    Done(false);
    return;
  }

  // Reset the index, so we know when we're done.
  DCHECK_EQ(current_index_, 0);
  current_index_ = paths.size();

  for (size_t i = 0; i < paths.size(); ++i) {
    file_system->GetResourceEntry(
        paths[i],
        base::Bind(&FileTaskExecutor::OnFileEntryFetched,
                   weak_ptr_factory_.GetWeakPtr()));
  }
}

void FileTaskExecutor::OnFileEntryFetched(FileError error,
                                          scoped_ptr<ResourceEntry> entry) {
  // Here, we are only interested in files.
  if (entry.get() && !entry->has_file_specific_info())
    error = FILE_ERROR_NOT_FOUND;

  DriveServiceInterface* drive_service =
      util::GetDriveServiceByProfile(profile_);

  if (!drive_service || error != FILE_ERROR_OK) {
    Done(false);
    return;
  }

  // Send off a request for the drive service to authorize the apps for the
  // current document entry for this document so we can get the
  // open-with-<app_id> urls from the document entry.
  drive_service->AuthorizeApp(entry->resource_id(),
                              app_id_,
                              base::Bind(&FileTaskExecutor::OnAppAuthorized,
                                         weak_ptr_factory_.GetWeakPtr(),
                                         entry->resource_id()));
}

void FileTaskExecutor::OnAppAuthorized(const std::string& resource_id,
                                       google_apis::GDataErrorCode error,
                                       const GURL& open_link) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  DriveIntegrationService* service =
      DriveIntegrationServiceFactory::FindForProfile(profile_);
  if (!service || !service->IsMounted() ||
      error != google_apis::HTTP_SUCCESS || open_link.is_empty()) {
    Done(false);
    return;
  }

  {
    chrome::ScopedTabbedBrowserDisplayer displayer(
         profile_, chrome::HOST_DESKTOP_TYPE_ASH);
    chrome::AddSelectedTabWithURL(displayer.browser(), open_link,
                                  content::PAGE_TRANSITION_LINK);
    // Since the ScopedTabbedBrowserDisplayer does not guarantee that the
    // browser will be shown on the active desktop, we ensure the visibility.
    multi_user_util::MoveWindowToCurrentDesktop(
        displayer.browser()->window()->GetNativeWindow());
  }

  // We're done with this file.  If this is the last one, then we're done.
  current_index_--;
  DCHECK_GE(current_index_, 0);
  if (current_index_ == 0)
    Done(true);
}

void FileTaskExecutor::Done(bool success) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  if (!done_.is_null())
    done_.Run(success);
  delete this;
}

}  // namespace drive
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const wchar_t kConsoleTestPage[] = L"files/devtools/console_test_page.html";
const wchar_t kDebuggerTestPage[] = L"files/devtools/debugger_test_page.html";
const wchar_t kEvalTestPage[] = L"files/devtools/eval_test_page.html";
const wchar_t kJsPage[] = L"files/devtools/js_page.html";
const wchar_t kResourceTestPage[] = L"files/devtools/resource_test_page.html";
const wchar_t kSimplePage[] = L"files/devtools/simple_page.html";
const wchar_t kSyntaxErrorTestPage[] =
    L"files/devtools/script_syntax_error.html";
const wchar_t kDebuggerStepTestPage[] =
    L"files/devtools/debugger_step.html";
const wchar_t kDebuggerClosurePage[] =
    L"files/devtools/debugger_closure.html";
const wchar_t kDebuggerIntrinsicPropertiesPage[] =
    L"files/devtools/debugger_intrinsic_properties.html";
const wchar_t kCompletionOnPause[] =
    L"files/devtools/completion_on_pause.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::wstring& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;

    // At first check that JavaScript part of the front-end is loaded by
    // checking that global variable uiTests exists(it's created after all js
    // files have been loaded) and has runTest method.
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_->render_view_host(),
            L"",
            L"window.domAutomationController.send("
            L"'' + (window.uiTests && (typeof uiTests.runTest)));",
            &result));

    if (result == "function") {
      ASSERT_TRUE(
          ui_test_utils::ExecuteJavaScriptAndExtractString(
              client_contents_->render_view_host(),
              L"",
              UTF8ToWide(StringPrintf("uiTests.runTest('%s')",
                                      test_name.c_str())),
              &result));
      EXPECT_EQ("[OK]", result);
    } else {
      FAIL() << "DevTools front-end is broken.";
    }
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::wstring& test_page) {
    HTTPTestServer* server = StartHTTPServer();
    GURL url = server->TestServerPageW(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    TabContents* tab = browser()->GetTabContentsAt(0);
    inspected_rvh_ = tab->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    // UnregisterDevToolsClientHostFor may destroy window_ so store the browser
    // first.
    Browser* browser = window_->browser();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);
    BrowserClosedObserver close_observer(browser);
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

// WebInspector opens.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHostIsPresent) {
  RunTest("testHostIsPresent", kSimplePage);
}

// Tests elements panel basics.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestElementsTreeRoot) {
  RunTest("testElementsTreeRoot", kSimplePage);
}

// Tests main resource load.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMainResource) {
  RunTest("testMainResource", kSimplePage);
}

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Tests resource headers.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestResourceHeaders) {
  RunTest("testResourceHeaders", kResourceTestPage);
}

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
  RunTest("testShowScriptsTab", kDebuggerTestPage);
}

// Tests that scripts are not duplicated after Scripts Panel switch.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestNoScriptDuplicatesOnPanelSwitch) {
  RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}

// Tests set breakpoint.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestSetBreakpoint) {
  RunTest("testSetBreakpoint", kDebuggerTestPage);
}

// Tests eval on call frame.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalOnCallFrame) {
  RunTest("testEvalOnCallFrame", kDebuggerTestPage);
}

// Tests step over functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOver) {
  RunTest("testStepOver", kDebuggerStepTestPage);
}

// Tests step out functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOut) {
  RunTest("testStepOut", kDebuggerStepTestPage);
}

// Tests step in functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepIn) {
  RunTest("testStepIn", kDebuggerStepTestPage);
}

// Tests that scope can be expanded and contains expected variables.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestExpandScope) {
  RunTest("testExpandScope", kDebuggerClosurePage);
}

// Tests that intrinsic properties(__proto__, prototype, constructor) are
// present.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDebugIntrinsicProperties) {
  RunTest("testDebugIntrinsicProperties", kDebuggerIntrinsicPropertiesPage);
}

// Tests that execution continues automatically when there is a syntax error in
// script and DevTools are open.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestAutoContinueOnSyntaxError) {
  RunTest("testAutoContinueOnSyntaxError", kSyntaxErrorTestPage);
}

IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCompletionOnPause) {
  RunTest("testCompletionOnPause", kCompletionOnPause);
}

// Tests that 'Pause' button works for eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) {
  RunTest("testPauseInEval", kDebuggerTestPage);
}

// Tests console eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleEval) {
  RunTest("testConsoleEval", kConsoleTestPage);
}

// Tests console log.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleLog) {
  RunTest("testConsoleLog", kConsoleTestPage);
}

// Tests eval global values.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalGlobal) {
  RunTest("testEvalGlobal", kEvalTestPage);
}

}  // namespace
<commit_msg>DevTools: temporarily disable completion test which fails on Linux<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const wchar_t kConsoleTestPage[] = L"files/devtools/console_test_page.html";
const wchar_t kDebuggerTestPage[] = L"files/devtools/debugger_test_page.html";
const wchar_t kEvalTestPage[] = L"files/devtools/eval_test_page.html";
const wchar_t kJsPage[] = L"files/devtools/js_page.html";
const wchar_t kResourceTestPage[] = L"files/devtools/resource_test_page.html";
const wchar_t kSimplePage[] = L"files/devtools/simple_page.html";
const wchar_t kSyntaxErrorTestPage[] =
    L"files/devtools/script_syntax_error.html";
const wchar_t kDebuggerStepTestPage[] =
    L"files/devtools/debugger_step.html";
const wchar_t kDebuggerClosurePage[] =
    L"files/devtools/debugger_closure.html";
const wchar_t kDebuggerIntrinsicPropertiesPage[] =
    L"files/devtools/debugger_intrinsic_properties.html";
const wchar_t kCompletionOnPause[] =
    L"files/devtools/completion_on_pause.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::wstring& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;

    // At first check that JavaScript part of the front-end is loaded by
    // checking that global variable uiTests exists(it's created after all js
    // files have been loaded) and has runTest method.
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_->render_view_host(),
            L"",
            L"window.domAutomationController.send("
            L"'' + (window.uiTests && (typeof uiTests.runTest)));",
            &result));

    if (result == "function") {
      ASSERT_TRUE(
          ui_test_utils::ExecuteJavaScriptAndExtractString(
              client_contents_->render_view_host(),
              L"",
              UTF8ToWide(StringPrintf("uiTests.runTest('%s')",
                                      test_name.c_str())),
              &result));
      EXPECT_EQ("[OK]", result);
    } else {
      FAIL() << "DevTools front-end is broken.";
    }
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::wstring& test_page) {
    HTTPTestServer* server = StartHTTPServer();
    GURL url = server->TestServerPageW(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    TabContents* tab = browser()->GetTabContentsAt(0);
    inspected_rvh_ = tab->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    // UnregisterDevToolsClientHostFor may destroy window_ so store the browser
    // first.
    Browser* browser = window_->browser();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);
    BrowserClosedObserver close_observer(browser);
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

// WebInspector opens.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHostIsPresent) {
  RunTest("testHostIsPresent", kSimplePage);
}

// Tests elements panel basics.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestElementsTreeRoot) {
  RunTest("testElementsTreeRoot", kSimplePage);
}

// Tests main resource load.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMainResource) {
  RunTest("testMainResource", kSimplePage);
}

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Tests resource headers.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestResourceHeaders) {
  RunTest("testResourceHeaders", kResourceTestPage);
}

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
  RunTest("testShowScriptsTab", kDebuggerTestPage);
}

// Tests that scripts are not duplicated after Scripts Panel switch.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestNoScriptDuplicatesOnPanelSwitch) {
  RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}

// Tests set breakpoint.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestSetBreakpoint) {
  RunTest("testSetBreakpoint", kDebuggerTestPage);
}

// Tests eval on call frame.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalOnCallFrame) {
  RunTest("testEvalOnCallFrame", kDebuggerTestPage);
}

// Tests step over functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOver) {
  RunTest("testStepOver", kDebuggerStepTestPage);
}

// Tests step out functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOut) {
  RunTest("testStepOut", kDebuggerStepTestPage);
}

// Tests step in functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepIn) {
  RunTest("testStepIn", kDebuggerStepTestPage);
}

// Tests that scope can be expanded and contains expected variables.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestExpandScope) {
  RunTest("testExpandScope", kDebuggerClosurePage);
}

// Tests that intrinsic properties(__proto__, prototype, constructor) are
// present.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDebugIntrinsicProperties) {
  RunTest("testDebugIntrinsicProperties", kDebuggerIntrinsicPropertiesPage);
}

// Tests that execution continues automatically when there is a syntax error in
// script and DevTools are open.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestAutoContinueOnSyntaxError) {
  RunTest("testAutoContinueOnSyntaxError", kSyntaxErrorTestPage);
}

IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestCompletionOnPause) {
  RunTest("testCompletionOnPause", kCompletionOnPause);
}

// Tests that 'Pause' button works for eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) {
  RunTest("testPauseInEval", kDebuggerTestPage);
}

// Tests console eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleEval) {
  RunTest("testConsoleEval", kConsoleTestPage);
}

// Tests console log.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleLog) {
  RunTest("testConsoleLog", kConsoleTestPage);
}

// Tests eval global values.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalGlobal) {
  RunTest("testEvalGlobal", kEvalTestPage);
}

}  // namespace
<|endoftext|>