<commit_before>/* Copyright 2019 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/lite/python/optimize/calibration_wrapper.h"

#include <memory>
#include <sstream>
#include <string>

#include "absl/memory/memory.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/python/interpreter_wrapper/numpy.h"
#include "tensorflow/lite/python/interpreter_wrapper/python_error_reporter.h"
#include "tensorflow/lite/python/interpreter_wrapper/python_utils.h"
#include "tensorflow/lite/tools/optimize/calibration/calibration_reader.h"
#include "tensorflow/lite/tools/optimize/calibration/calibrator.h"
#include "tensorflow/lite/tools/optimize/quantize_model.h"

#define TFLITE_PY_CHECK(x)               \
  if ((x) != kTfLiteOk) {                \
    return error_reporter_->exception(); \
  }

#define TFLITE_PY_ENSURE_VALID_INTERPRETER()                               \
  if (!interpreter_) {                                                     \
    PyErr_SetString(PyExc_ValueError, "Interpreter was not initialized."); \
    return nullptr;                                                        \
  }

namespace tflite {
namespace calibration_wrapper {

namespace {

using python_utils::PyDecrefDeleter;

std::unique_ptr<tflite::ModelT> CreateMutableModel(const tflite::Model& model) {
  auto copied_model = absl::make_unique<tflite::ModelT>();
  model.UnPackTo(copied_model.get(), nullptr);
  return copied_model;
}

bool NoOpModel(const tflite::FlatBufferModel& model) {
  return model->subgraphs()->size() == 1 &&
         (!model->subgraphs()->begin()->operators() ||
          model->subgraphs()->begin()->operators()->size() == 0);
}

inline TensorType TfLiteTypeToSchemaType(TfLiteType type) {
  switch (type) {
    case kTfLiteNoType:
      return TensorType_FLOAT32;  // TODO(b/129336260): No schema type for none.
    case kTfLiteFloat32:
      return TensorType_FLOAT32;
    case kTfLiteFloat16:
      return TensorType_FLOAT16;
    case kTfLiteFloat64:
      return TensorType_FLOAT64;
    case kTfLiteInt32:
      return TensorType_INT32;
    case kTfLiteUInt8:
      return TensorType_UINT8;
    case kTfLiteInt8:
      return TensorType_INT8;
    case kTfLiteInt64:
      return TensorType_INT64;
    case kTfLiteString:
      return TensorType_STRING;
    case kTfLiteBool:
      return TensorType_BOOL;
    case kTfLiteInt16:
      return TensorType_INT16;
    case kTfLiteComplex64:
      return TensorType_COMPLEX64;
    case kTfLiteComplex128:
      return TensorType_COMPLEX128;
  }
  // No default to get compiler error when new type is introduced.
}

}  // namespace

CalibrationWrapper::CalibrationWrapper(
    std::unique_ptr<tflite::Interpreter> interpreter,
    std::unique_ptr<tflite::ops::builtin::BuiltinOpResolver> resolver,
    std::unique_ptr<tflite::interpreter_wrapper::PythonErrorReporter>
        error_reporter,
    std::unique_ptr<tflite::FlatBufferModel> model,
    std::unique_ptr<tflite::optimize::calibration::CalibrationReader> reader,
    std::unique_ptr<std::string> model_str)
    : interpreter_(std::move(interpreter)),
      error_reporter_(std::move(error_reporter)),
      resolver_(std::move(resolver)),
      model_(std::move(model)),
      reader_(std::move(reader)),
      model_str_(std::move(model_str)) {}

CalibrationWrapper::~CalibrationWrapper() {}

PyObject* CalibrationWrapper::Prepare() {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();
  TFLITE_PY_CHECK(interpreter_->AllocateTensors());
  TFLITE_PY_CHECK(interpreter_->ResetVariableTensors());
  Py_RETURN_NONE;
}

PyObject* CalibrationWrapper::Prepare(PyObject* input_shapes) {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();
  if (!PyList_Check(input_shapes)) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input shapes: expected shapes to be a list.");
    return nullptr;
  }

  const size_t inputs_size = PyList_Size(input_shapes);
  if (inputs_size != interpreter_->inputs().size()) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input shapes: expected %ld items got %ld items.",
                 interpreter_->inputs().size(), inputs_size);
    return nullptr;
  }

  for (size_t i = 0; i < inputs_size; i++) {
    PyObject* shape = PyList_GetItem(input_shapes, i);
    if (!shape || !PyList_Check(shape)) {
      PyErr_Format(PyExc_ValueError,
                   "Invalid %ld input shape: expected to be a list.", i);
      return nullptr;
    }
    std::vector<int> dims;
    for (size_t dim_index = 0; dim_index < PyList_Size(shape); ++dim_index) {
      PyObject* dim = PyList_GetItem(shape, dim_index);
      dims.push_back(PyLong_AsLong(dim));
    }
    int input_tensor_idx = interpreter_->inputs()[i];
    if (interpreter_->ResizeInputTensor(input_tensor_idx, dims) != kTfLiteOk) {
      PyErr_Format(PyExc_ValueError, "Failed to resize %ld input tensor.", i);
      return nullptr;
    }
  }

  return Prepare();
}

PyObject* CalibrationWrapper::FeedTensor(PyObject* input_value) {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();
  if (!PyList_Check(input_value)) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input type: expected input to be a list.");
    return nullptr;
  }

  const size_t inputs_size = PyList_Size(input_value);

  if (inputs_size != interpreter_->inputs().size()) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input size: expected %ld items got %ld items.",
                 interpreter_->inputs().size(), inputs_size);
    return nullptr;
  }

  for (size_t i = 0; i < inputs_size; i++) {
    PyObject* input = PyList_GetItem(input_value, i);
    if (!input) {
      return nullptr;
    }
    int input_tensor_idx = interpreter_->inputs()[i];
    if (!SetTensor(input_tensor_idx, input)) {
      return nullptr;
    }
  }

  TFLITE_PY_CHECK(interpreter_->Invoke());
  Py_RETURN_NONE;
}

PyObject* CalibrationWrapper::SetTensor(int index, PyObject* value) {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();

  std::unique_ptr<PyObject, PyDecrefDeleter> array_safe(
      PyArray_FromAny(value, nullptr, 0, 0, NPY_ARRAY_CARRAY, nullptr));
  if (!array_safe) {
    PyErr_SetString(PyExc_ValueError,
                    "Failed to convert value into readable tensor.");
    return nullptr;
  }

  PyArrayObject* array = reinterpret_cast<PyArrayObject*>(array_safe.get());
  const TfLiteTensor* tensor = interpreter_->tensor(index);

  if (python_utils::TfLiteTypeFromPyArray(array) != tensor->type) {
    PyErr_Format(PyExc_ValueError,
                 "Cannot set tensor:"
                 " Got value of type %s"
                 " but expected type %s for input %d, name: %s ",
                 TfLiteTypeGetName(python_utils::TfLiteTypeFromPyArray(array)),
                 TfLiteTypeGetName(tensor->type), index, tensor->name);
    return nullptr;
  }

  if (PyArray_NDIM(array) != tensor->dims->size) {
    PyErr_Format(
        PyExc_ValueError,
        "Cannot set tensor: Dimension count mismatch, expected %d but found %d",
        tensor->dims->size, PyArray_NDIM(array));
    return nullptr;
  }

  std::vector<int> dims(PyArray_NDIM(array));
  bool has_unknown_dims = false;
  for (int j = 0; j < PyArray_NDIM(array); j++) {
    // Ensure the calibration data input shape is the same as the model input
    // shape unless the dimension is unknown.
    if (tensor->dims_signature->size == tensor->dims->size &&
        tensor->dims_signature->data[j] == -1) {
      has_unknown_dims = true;
    } else if (tensor->dims->data[j] != PyArray_SHAPE(array)[j]) {
      PyErr_Format(PyExc_ValueError,
                   "Cannot set tensor: Size mismatch, expected %d for dim "
                   "%d but found %ld",
                   tensor->dims->data[j], j, PyArray_SHAPE(array)[j]);
      return nullptr;
    }
    dims[j] = PyArray_SHAPE(array)[j];
  }

  // Resize the input tensor if there are unknown dimensions.
  if (has_unknown_dims) {
    // Does strict checking on the `ResizeInputTensor` call.
    TFLITE_PY_CHECK(interpreter_->ResizeInputTensorStrict(index, dims));
    TFLITE_PY_CHECK(interpreter_->AllocateTensors());
  }

  tensor = interpreter_->tensor(index);

  size_t size = PyArray_NBYTES(array);

  if (tensor->type == kTfLiteString) {
    tflite::DynamicBuffer buffer;
    buffer.AddString(reinterpret_cast<const char*>(PyArray_BYTES(array)), size);
    buffer.WriteToTensor(interpreter_->tensor(index), /*new_shape=*/nullptr);
    Py_RETURN_NONE;
  }

  if (size != tensor->bytes) {
    PyErr_Format(PyExc_ValueError,
                 "numpy array had %zu bytes but expected %zu bytes.", size,
                 tensor->bytes);
    return nullptr;
  }
  memcpy(tensor->data.raw, PyArray_DATA(array), size);
  Py_RETURN_NONE;
}

PyObject* CalibrationWrapper::Calibrate() {
  auto tflite_model = CreateMutableModel(*model_->GetModel());
  reader_->AddCalibrationToModel(tflite_model.get(), /*update=*/false);
  flatbuffers::FlatBufferBuilder builder;
  auto loc = tflite::Model::Pack(builder, tflite_model.get());
  tflite::FinishModelBuffer(builder, loc);
  return python_utils::ConvertToPyString(
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
      builder.GetSize());
}

PyObject* CalibrationWrapper::QuantizeModel(int input_py_type,
                                            int output_py_type,
                                            bool allow_float,
                                            int activations_py_type) {
  if (NoOpModel(*model_)) {
    return python_utils::ConvertToPyString(model_str_->data(),
                                           model_str_->size());
  }

  TfLiteType input_type = python_utils::TfLiteTypeFromPyType(input_py_type);
  TfLiteType output_type = python_utils::TfLiteTypeFromPyType(output_py_type);
  TfLiteType activations_type =
      python_utils::TfLiteTypeFromPyType(activations_py_type);

  if (input_type == kTfLiteNoType || output_type == kTfLiteNoType) {
    PyErr_SetString(PyExc_ValueError,
                    "Input/output type cannot be kTfLiteNoType");
    return nullptr;
  }
  auto tflite_model = CreateMutableModel(*model_->GetModel());
  reader_->AddCalibrationToModel(tflite_model.get(), /*update=*/false);
  flatbuffers::FlatBufferBuilder builder;
  auto status = kTfLiteOk;

  status = tflite::optimize::QuantizeModelAllOperators(
      &builder, tflite_model.get(), TfLiteTypeToSchemaType(input_type),
      TfLiteTypeToSchemaType(output_type), allow_float,
      TfLiteTypeToSchemaType(activations_type), error_reporter_.get());

  if (status != kTfLiteOk) {
    error_reporter_->exception();
    return nullptr;
  }

  return python_utils::ConvertToPyString(
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
      builder.GetSize());
}

PyObject* CalibrationWrapper::QuantizeModel(int input_py_type,
                                            int output_py_type,
                                            bool allow_float,
                                            const char* operator_output_name) {
  string op_name = std::string(operator_output_name);

  TfLiteType input_type = python_utils::TfLiteTypeFromPyType(input_py_type);
  TfLiteType output_type = python_utils::TfLiteTypeFromPyType(output_py_type);
  if (input_type == kTfLiteNoType || output_type == kTfLiteNoType) {
    PyErr_SetString(PyExc_ValueError,
                    "Input/output type cannot be kTfLiteNoType");
    return nullptr;
  }
  auto tflite_model = CreateMutableModel(*model_->GetModel());
  reader_->AddCalibrationToModel(tflite_model.get(), /*update=*/false);
  flatbuffers::FlatBufferBuilder builder;
  auto status = tflite::optimize::QuantizeModel(
      &builder, tflite_model.get(), TfLiteTypeToSchemaType(input_type),
      TfLiteTypeToSchemaType(output_type), allow_float, {op_name},
      TensorType_INT8, error_reporter_.get());
  if (status != kTfLiteOk) {
    error_reporter_->exception();
    return nullptr;
  }

  return python_utils::ConvertToPyString(
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
      builder.GetSize());
}

/*static*/ CalibrationWrapper* CalibrationWrapper::CreateWrapperCPPFromBuffer(
    PyObject* data) {
  using tflite::interpreter_wrapper::PythonErrorReporter;
  char* buf = nullptr;
  Py_ssize_t length;
  std::unique_ptr<PythonErrorReporter> error_reporter(new PythonErrorReporter);
  ::tflite::python::ImportNumpy();

  if (python_utils::ConvertFromPyString(data, &buf, &length) == -1) {
    return nullptr;
  }
  std::unique_ptr<tflite::FlatBufferModel> model =
      tflite::FlatBufferModel::BuildFromBuffer(buf, length,
                                               error_reporter.get());
  if (!model) {
    PyErr_Format(PyExc_ValueError, "Invalid model");
    return nullptr;
  }
  auto resolver = absl::make_unique<tflite::ops::builtin::BuiltinOpResolver>();
  std::unique_ptr<tflite::Interpreter> interpreter;
  std::unique_ptr<tflite::optimize::calibration::CalibrationReader> reader;
  auto status = tflite::optimize::calibration::BuildLoggingInterpreter(
      *model, *resolver, &interpreter, &reader);
  if (status != kTfLiteOk) {
    error_reporter->exception();
    return nullptr;
  }

  auto model_str = std::make_unique<std::string>(buf, length);
  // If we are not going to use this string during quantization, reset the
  // pointer and release the memory.
  if (!NoOpModel(*model)) {
    model_str.reset();
  }

  auto wrapper = new CalibrationWrapper(
      std::move(interpreter), std::move(resolver), std::move(error_reporter),
      std::move(model), std::move(reader), std::move(model_str));
  return wrapper;
}

}  // namespace calibration_wrapper
}  // namespace tflite
<commit_msg>Internal fix on converter.<commit_after>/* Copyright 2019 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/lite/python/optimize/calibration_wrapper.h"

#include <memory>
#include <sstream>
#include <string>

#include "absl/memory/memory.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/python/interpreter_wrapper/numpy.h"
#include "tensorflow/lite/python/interpreter_wrapper/python_error_reporter.h"
#include "tensorflow/lite/python/interpreter_wrapper/python_utils.h"
#include "tensorflow/lite/tools/optimize/calibration/calibration_reader.h"
#include "tensorflow/lite/tools/optimize/calibration/calibrator.h"
#include "tensorflow/lite/tools/optimize/quantize_model.h"

#define TFLITE_PY_CHECK(x)               \
  if ((x) != kTfLiteOk) {                \
    return error_reporter_->exception(); \
  }

#define TFLITE_PY_ENSURE_VALID_INTERPRETER()                               \
  if (!interpreter_) {                                                     \
    PyErr_SetString(PyExc_ValueError, "Interpreter was not initialized."); \
    return nullptr;                                                        \
  }

namespace tflite {
namespace calibration_wrapper {

namespace {

using python_utils::PyDecrefDeleter;

std::unique_ptr<tflite::ModelT> CreateMutableModel(const tflite::Model& model) {
  auto copied_model = absl::make_unique<tflite::ModelT>();
  model.UnPackTo(copied_model.get(), nullptr);
  return copied_model;
}

bool NoOpModel(const tflite::FlatBufferModel& model) {
  return model->subgraphs()->size() == 1 &&
         (!model->subgraphs()->begin()->operators() ||
          model->subgraphs()->begin()->operators()->size() == 0);
}

inline TensorType TfLiteTypeToSchemaType(TfLiteType type) {
  switch (type) {
    case kTfLiteNoType:
      return TensorType_FLOAT32;  // TODO(b/129336260): No schema type for none.
    case kTfLiteFloat32:
      return TensorType_FLOAT32;
    case kTfLiteFloat16:
      return TensorType_FLOAT16;
    case kTfLiteFloat64:
      return TensorType_FLOAT64;
    case kTfLiteInt32:
      return TensorType_INT32;
    case kTfLiteUInt8:
      return TensorType_UINT8;
    case kTfLiteInt8:
      return TensorType_INT8;
    case kTfLiteInt64:
      return TensorType_INT64;
    case kTfLiteString:
      return TensorType_STRING;
    case kTfLiteBool:
      return TensorType_BOOL;
    case kTfLiteInt16:
      return TensorType_INT16;
    case kTfLiteComplex64:
      return TensorType_COMPLEX64;
    case kTfLiteComplex128:
      return TensorType_COMPLEX128;
  }
  // No default to get compiler error when new type is introduced.
}

}  // namespace

CalibrationWrapper::CalibrationWrapper(
    std::unique_ptr<tflite::Interpreter> interpreter,
    std::unique_ptr<tflite::ops::builtin::BuiltinOpResolver> resolver,
    std::unique_ptr<tflite::interpreter_wrapper::PythonErrorReporter>
        error_reporter,
    std::unique_ptr<tflite::FlatBufferModel> model,
    std::unique_ptr<tflite::optimize::calibration::CalibrationReader> reader,
    std::unique_ptr<std::string> model_str)
    : interpreter_(std::move(interpreter)),
      error_reporter_(std::move(error_reporter)),
      resolver_(std::move(resolver)),
      model_(std::move(model)),
      reader_(std::move(reader)),
      model_str_(std::move(model_str)) {}

CalibrationWrapper::~CalibrationWrapper() {}

PyObject* CalibrationWrapper::Prepare() {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();
  TFLITE_PY_CHECK(interpreter_->AllocateTensors());
  TFLITE_PY_CHECK(interpreter_->ResetVariableTensors());
  Py_RETURN_NONE;
}

PyObject* CalibrationWrapper::Prepare(PyObject* input_shapes) {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();
  if (!PyList_Check(input_shapes)) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input shapes: expected shapes to be a list.");
    return nullptr;
  }

  const size_t inputs_size = PyList_Size(input_shapes);
  if (inputs_size != interpreter_->inputs().size()) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input shapes: expected %ld items got %ld items.",
                 interpreter_->inputs().size(), inputs_size);
    return nullptr;
  }

  for (size_t i = 0; i < inputs_size; i++) {
    PyObject* shape = PyList_GetItem(input_shapes, i);
    if (!shape || !PyList_Check(shape)) {
      PyErr_Format(PyExc_ValueError,
                   "Invalid %ld input shape: expected to be a list.", i);
      return nullptr;
    }
    std::vector<int> dims;
    for (size_t dim_index = 0; dim_index < PyList_Size(shape); ++dim_index) {
      PyObject* dim = PyList_GetItem(shape, dim_index);
      dims.push_back(PyLong_AsLong(dim));
    }
    int input_tensor_idx = interpreter_->inputs()[i];
    if (interpreter_->ResizeInputTensor(input_tensor_idx, dims) != kTfLiteOk) {
      PyErr_Format(PyExc_ValueError, "Failed to resize %ld input tensor.", i);
      return nullptr;
    }
  }

  return Prepare();
}

PyObject* CalibrationWrapper::FeedTensor(PyObject* input_value) {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();
  if (!PyList_Check(input_value)) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input type: expected input to be a list.");
    return nullptr;
  }

  const size_t inputs_size = PyList_Size(input_value);

  if (inputs_size != interpreter_->inputs().size()) {
    PyErr_Format(PyExc_ValueError,
                 "Invalid input size: expected %ld items got %ld items.",
                 interpreter_->inputs().size(), inputs_size);
    return nullptr;
  }

  for (size_t i = 0; i < inputs_size; i++) {
    PyObject* input = PyList_GetItem(input_value, i);
    if (!input) {
      return nullptr;
    }
    int input_tensor_idx = interpreter_->inputs()[i];
    if (!SetTensor(input_tensor_idx, input)) {
      return nullptr;
    }
  }

  TFLITE_PY_CHECK(interpreter_->Invoke());
  Py_RETURN_NONE;
}

PyObject* CalibrationWrapper::SetTensor(int index, PyObject* value) {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();

  std::unique_ptr<PyObject, PyDecrefDeleter> array_safe(
      PyArray_FromAny(value, nullptr, 0, 0, NPY_ARRAY_CARRAY, nullptr));
  if (!array_safe) {
    PyErr_SetString(PyExc_ValueError,
                    "Failed to convert value into readable tensor.");
    return nullptr;
  }

  PyArrayObject* array = reinterpret_cast<PyArrayObject*>(array_safe.get());
  const TfLiteTensor* tensor = interpreter_->tensor(index);

  if (python_utils::TfLiteTypeFromPyArray(array) != tensor->type) {
    PyErr_Format(PyExc_ValueError,
                 "Cannot set tensor:"
                 " Got value of type %s"
                 " but expected type %s for input %d, name: %s ",
                 TfLiteTypeGetName(python_utils::TfLiteTypeFromPyArray(array)),
                 TfLiteTypeGetName(tensor->type), index, tensor->name);
    return nullptr;
  }

  if (PyArray_NDIM(array) != tensor->dims->size) {
    PyErr_Format(
        PyExc_ValueError,
        "Cannot set tensor: Dimension count mismatch, expected %d but found %d",
        tensor->dims->size, PyArray_NDIM(array));
    return nullptr;
  }

  std::vector<int> dims(PyArray_NDIM(array));
  bool has_unknown_dims = false;
  for (int j = 0; j < PyArray_NDIM(array); j++) {
    // Ensure the calibration data input shape is the same as the model input
    // shape unless the dimension is unknown.
    if (tensor->dims_signature != nullptr &&
        tensor->dims_signature->size == tensor->dims->size &&
        tensor->dims_signature->data[j] == -1) {
      has_unknown_dims = true;
    } else if (tensor->dims->data[j] != PyArray_SHAPE(array)[j]) {
      PyErr_Format(PyExc_ValueError,
                   "Cannot set tensor: Size mismatch, expected %d for dim "
                   "%d but found %ld",
                   tensor->dims->data[j], j, PyArray_SHAPE(array)[j]);
      return nullptr;
    }
    dims[j] = PyArray_SHAPE(array)[j];
  }

  // Resize the input tensor if there are unknown dimensions.
  if (has_unknown_dims) {
    // Does strict checking on the `ResizeInputTensor` call.
    TFLITE_PY_CHECK(interpreter_->ResizeInputTensorStrict(index, dims));
    TFLITE_PY_CHECK(interpreter_->AllocateTensors());
  }

  tensor = interpreter_->tensor(index);

  size_t size = PyArray_NBYTES(array);

  if (tensor->type == kTfLiteString) {
    tflite::DynamicBuffer buffer;
    buffer.AddString(reinterpret_cast<const char*>(PyArray_BYTES(array)), size);
    buffer.WriteToTensor(interpreter_->tensor(index), /*new_shape=*/nullptr);
    Py_RETURN_NONE;
  }

  if (size != tensor->bytes) {
    PyErr_Format(PyExc_ValueError,
                 "numpy array had %zu bytes but expected %zu bytes.", size,
                 tensor->bytes);
    return nullptr;
  }
  memcpy(tensor->data.raw, PyArray_DATA(array), size);
  Py_RETURN_NONE;
}

PyObject* CalibrationWrapper::Calibrate() {
  auto tflite_model = CreateMutableModel(*model_->GetModel());
  reader_->AddCalibrationToModel(tflite_model.get(), /*update=*/false);
  flatbuffers::FlatBufferBuilder builder;
  auto loc = tflite::Model::Pack(builder, tflite_model.get());
  tflite::FinishModelBuffer(builder, loc);
  return python_utils::ConvertToPyString(
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
      builder.GetSize());
}

PyObject* CalibrationWrapper::QuantizeModel(int input_py_type,
                                            int output_py_type,
                                            bool allow_float,
                                            int activations_py_type) {
  if (NoOpModel(*model_)) {
    return python_utils::ConvertToPyString(model_str_->data(),
                                           model_str_->size());
  }

  TfLiteType input_type = python_utils::TfLiteTypeFromPyType(input_py_type);
  TfLiteType output_type = python_utils::TfLiteTypeFromPyType(output_py_type);
  TfLiteType activations_type =
      python_utils::TfLiteTypeFromPyType(activations_py_type);

  if (input_type == kTfLiteNoType || output_type == kTfLiteNoType) {
    PyErr_SetString(PyExc_ValueError,
                    "Input/output type cannot be kTfLiteNoType");
    return nullptr;
  }
  auto tflite_model = CreateMutableModel(*model_->GetModel());
  reader_->AddCalibrationToModel(tflite_model.get(), /*update=*/false);
  flatbuffers::FlatBufferBuilder builder;
  auto status = kTfLiteOk;

  status = tflite::optimize::QuantizeModelAllOperators(
      &builder, tflite_model.get(), TfLiteTypeToSchemaType(input_type),
      TfLiteTypeToSchemaType(output_type), allow_float,
      TfLiteTypeToSchemaType(activations_type), error_reporter_.get());

  if (status != kTfLiteOk) {
    error_reporter_->exception();
    return nullptr;
  }

  return python_utils::ConvertToPyString(
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
      builder.GetSize());
}

PyObject* CalibrationWrapper::QuantizeModel(int input_py_type,
                                            int output_py_type,
                                            bool allow_float,
                                            const char* operator_output_name) {
  string op_name = std::string(operator_output_name);

  TfLiteType input_type = python_utils::TfLiteTypeFromPyType(input_py_type);
  TfLiteType output_type = python_utils::TfLiteTypeFromPyType(output_py_type);
  if (input_type == kTfLiteNoType || output_type == kTfLiteNoType) {
    PyErr_SetString(PyExc_ValueError,
                    "Input/output type cannot be kTfLiteNoType");
    return nullptr;
  }
  auto tflite_model = CreateMutableModel(*model_->GetModel());
  reader_->AddCalibrationToModel(tflite_model.get(), /*update=*/false);
  flatbuffers::FlatBufferBuilder builder;
  auto status = tflite::optimize::QuantizeModel(
      &builder, tflite_model.get(), TfLiteTypeToSchemaType(input_type),
      TfLiteTypeToSchemaType(output_type), allow_float, {op_name},
      TensorType_INT8, error_reporter_.get());
  if (status != kTfLiteOk) {
    error_reporter_->exception();
    return nullptr;
  }

  return python_utils::ConvertToPyString(
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
      builder.GetSize());
}

/*static*/ CalibrationWrapper* CalibrationWrapper::CreateWrapperCPPFromBuffer(
    PyObject* data) {
  using tflite::interpreter_wrapper::PythonErrorReporter;
  char* buf = nullptr;
  Py_ssize_t length;
  std::unique_ptr<PythonErrorReporter> error_reporter(new PythonErrorReporter);
  ::tflite::python::ImportNumpy();

  if (python_utils::ConvertFromPyString(data, &buf, &length) == -1) {
    return nullptr;
  }
  std::unique_ptr<tflite::FlatBufferModel> model =
      tflite::FlatBufferModel::BuildFromBuffer(buf, length,
                                               error_reporter.get());
  if (!model) {
    PyErr_Format(PyExc_ValueError, "Invalid model");
    return nullptr;
  }
  auto resolver = absl::make_unique<tflite::ops::builtin::BuiltinOpResolver>();
  std::unique_ptr<tflite::Interpreter> interpreter;
  std::unique_ptr<tflite::optimize::calibration::CalibrationReader> reader;
  auto status = tflite::optimize::calibration::BuildLoggingInterpreter(
      *model, *resolver, &interpreter, &reader);
  if (status != kTfLiteOk) {
    error_reporter->exception();
    return nullptr;
  }

  auto model_str = std::make_unique<std::string>(buf, length);
  // If we are not going to use this string during quantization, reset the
  // pointer and release the memory.
  if (!NoOpModel(*model)) {
    model_str.reset();
  }

  auto wrapper = new CalibrationWrapper(
      std::move(interpreter), std::move(resolver), std::move(error_reporter),
      std::move(model), std::move(reader), std::move(model_str));
  return wrapper;
}

}  // namespace calibration_wrapper
}  // namespace tflite
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief Source for yanlr plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

// -- Imports ------------------------------------------------------------------------------------------------------------------------------

#include <iostream>

#include <kdb.hpp>
#include <kdberrors.h>

#include <antlr4-runtime.h>

#include "YAML.h"
#include "error_listener.hpp"
#include "listener.hpp"
#include "yaml_lexer.hpp"
#include "yanlr.hpp"

using CppKey = kdb::Key;
using CppKeySet = kdb::KeySet;

using antlr::YAML;

using antlr4::ANTLRInputStream;
using antlr4::CommonTokenStream;
using ParseTree = antlr4::tree::ParseTree;
using ParseTreeWalker = antlr4::tree::ParseTreeWalker;

using std::ifstream;

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

namespace
{
/**
 * @brief This function returns a key set containing the contract of this plugin.
 *
 * @return A contract describing the functionality of this plugin.
 */
KeySet * contractYanlr (void)
{
	return ksNew (30, keyNew ("system/elektra/modules/yanlr", KEY_VALUE, "yanlr plugin waits for your orders", KEY_END),
		      keyNew ("system/elektra/modules/yanlr/exports", KEY_END),
		      keyNew ("system/elektra/modules/yanlr/exports/get", KEY_FUNC, elektraYanlrGet, KEY_END),
#include ELEKTRA_README (yanlr)
		      keyNew ("system/elektra/modules/yanlr/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
}

/**
 * @brief This function parses the content of a YAML file and saves the result in the given key set.
 *
 * @param file This file contains the YAML content this function should parse.
 * @param keys The function adds the key set representing `file` in this key set, if the parsing process finished successfully.
 * @param parent The function uses this parameter to emit error information.
 *
 * @retval ELEKTRA_PLUGIN_STATUS_NO_UPDATE If parsing was successful and `keys` was not updated
 * @retval ELEKTRA_PLUGIN_STATUS_SUCCESS If parsing was successful and `keys` was updated
 * @retval ELEKTRA_PLUGIN_STATUS_ERROR If there was an error parsing `file`
 */
int parseYAML (ifstream & file, CppKeySet & keys, CppKey & parent)
{
	ANTLRInputStream input{ file };
	YAMLLexer lexer{ &input };
	CommonTokenStream tokens{ &lexer };
	YAML parser{ &tokens };
	ParseTreeWalker walker{};
	KeyListener listener{ parent };

	ErrorListener errorListener{};
	parser.removeErrorListeners ();
	parser.addErrorListener (&errorListener);

	ParseTree * tree = parser.yaml ();
	if (parser.getNumberOfSyntaxErrors () > 0)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_PARSE, parent.getKey (), errorListener.message ());
		return ELEKTRA_PLUGIN_STATUS_ERROR;
	}
	walker.walk (&listener, tree);

	auto readKeys = listener.keySet ();
	keys.append (readKeys);
	return readKeys.size () <= 0 ? ELEKTRA_PLUGIN_STATUS_NO_UPDATE : ELEKTRA_PLUGIN_STATUS_SUCCESS;
}

} // end namespace

extern "C" {
// ====================
// = Plugin Interface =
// ====================

/** @see elektraDocGet */
int elektraYanlrGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	auto parent = CppKey (parentKey);

	if (parent.getName () == "system/elektra/modules/yanlr")
	{
		KeySet * contract = contractYanlr ();
		ksAppend (returned, contract);
		ksDel (contract);
		parent.release ();

		return ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}

	ifstream file (parent.getString ());
	if (!file.is_open ())
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_COULD_NOT_OPEN, parent.getKey (), "Unable to open file “%s”",
				    parent.getString ().c_str ());
		return ELEKTRA_PLUGIN_STATUS_ERROR;
	}

	auto keys = CppKeySet{ returned };

	int status = parseYAML (file, keys, parent);

	keys.release ();
	parent.release ();

	return status;
}

Plugin * ELEKTRA_PLUGIN_EXPORT (yanlr)
{
	return elektraPluginExport ("yanlr", ELEKTRA_PLUGIN_GET, &elektraYanlrGet, ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<commit_msg>Yan LR: Use C++ style code for contract retrieval<commit_after>/**
 * @file
 *
 * @brief Source for yanlr plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

// -- Imports ------------------------------------------------------------------------------------------------------------------------------

#include <iostream>

#include <kdb.hpp>
#include <kdberrors.h>

#include <antlr4-runtime.h>

#include "YAML.h"
#include "error_listener.hpp"
#include "listener.hpp"
#include "yaml_lexer.hpp"
#include "yanlr.hpp"

using CppKey = kdb::Key;
using CppKeySet = kdb::KeySet;

using antlr::YAML;

using antlr4::ANTLRInputStream;
using antlr4::CommonTokenStream;
using ParseTree = antlr4::tree::ParseTree;
using ParseTreeWalker = antlr4::tree::ParseTreeWalker;

using std::ifstream;

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

namespace
{
/**
 * @brief This function returns a key set containing the contract of this plugin.
 *
 * @return A contract describing the functionality of this plugin.
 */
CppKeySet getContract ()
{
	return CppKeySet{ 30,
			  keyNew ("system/elektra/modules/yanlr", KEY_VALUE, "yanlr plugin waits for your orders", KEY_END),
			  keyNew ("system/elektra/modules/yanlr/exports", KEY_END),
			  keyNew ("system/elektra/modules/yanlr/exports/get", KEY_FUNC, elektraYanlrGet, KEY_END),
#include ELEKTRA_README (yanlr)
			  keyNew ("system/elektra/modules/yanlr/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END),
			  KS_END };
}

/**
 * @brief This function parses the content of a YAML file and saves the result in the given key set.
 *
 * @param file This file contains the YAML content this function should parse.
 * @param keys The function adds the key set representing `file` in this key set, if the parsing process finished successfully.
 * @param parent The function uses this parameter to emit error information.
 *
 * @retval ELEKTRA_PLUGIN_STATUS_NO_UPDATE If parsing was successful and `keys` was not updated
 * @retval ELEKTRA_PLUGIN_STATUS_SUCCESS If parsing was successful and `keys` was updated
 * @retval ELEKTRA_PLUGIN_STATUS_ERROR If there was an error parsing `file`
 */
int parseYAML (ifstream & file, CppKeySet & keys, CppKey & parent)
{
	ANTLRInputStream input{ file };
	YAMLLexer lexer{ &input };
	CommonTokenStream tokens{ &lexer };
	YAML parser{ &tokens };
	ParseTreeWalker walker{};
	KeyListener listener{ parent };

	ErrorListener errorListener{};
	parser.removeErrorListeners ();
	parser.addErrorListener (&errorListener);

	ParseTree * tree = parser.yaml ();
	if (parser.getNumberOfSyntaxErrors () > 0)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_PARSE, parent.getKey (), errorListener.message ());
		return ELEKTRA_PLUGIN_STATUS_ERROR;
	}
	walker.walk (&listener, tree);

	auto readKeys = listener.keySet ();
	keys.append (readKeys);
	return readKeys.size () <= 0 ? ELEKTRA_PLUGIN_STATUS_NO_UPDATE : ELEKTRA_PLUGIN_STATUS_SUCCESS;
}

} // end namespace

extern "C" {
// ====================
// = Plugin Interface =
// ====================

/** @see elektraDocGet */
int elektraYanlrGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	CppKey parent{ parentKey };
	CppKeySet keys{ returned };

	if (parent.getName () == "system/elektra/modules/yanlr")
	{
		keys.append (getContract ());
		keys.release ();
		parent.release ();

		return ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}

	ifstream file (parent.getString ());
	if (!file.is_open ())
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_COULD_NOT_OPEN, parent.getKey (), "Unable to open file “%s”",
				    parent.getString ().c_str ());
		return ELEKTRA_PLUGIN_STATUS_ERROR;
	}

	int status = parseYAML (file, keys, parent);

	keys.release ();
	parent.release ();

	return status;
}

Plugin * ELEKTRA_PLUGIN_EXPORT (yanlr)
{
	return elektraPluginExport ("yanlr", ELEKTRA_PLUGIN_GET, &elektraYanlrGet, ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<|endoftext|>


<commit_before>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#include "Bytecode.hpp"

namespace Implementation {

// These two static arrays describe language: all possible
// functions ans specifications.

static const char* const specifications_registry[] = {
    "r"
};

static const char* const functions_registry[] = {
    "eat", "go", "clon", "str", "left", "right", "back", "turn",
    "jg", "jl", "j", "je", "jfe", "jw", "jfw", "jb", "jfb"
};

// These four static arrays contain IDs of functions from
// functions_registry.

static const int two_parameter_functions[] = {
    8, 9
};

static const int one_parameter_functions[] = {
    0, 1, 3, 4, 5, 10, 11, 12, 13, 14, 15, 16
};

static const int spec_functions[] = {
    0, 1, 7
};

static const int non_argument_functions[] = {
    0, 1, 2, 3, 4, 5, 6
};

static void split(
    const std::string& str,
    char delimiter,
    Strings items
) {
    std::stringstream s_stream(str);
    std::string item;
    while (std::getline(s_stream, item, delimiter)) {
        if (!item.empty()) {
            items.push_back(item);
        }
    }
}

static int isParameter(const std::string& what) {
    bool is_parameter = true;
    for (int i = 0; i < what.size(); i++) {
        if (!isdigit(what[i])) {
            is_parameter = false;
        }
    }
    return (is_parameter) ? atoi(what.c_str()) : -1;
}

static bool isSpecification(const std::string& what) {
    size_t el_size = sizeof(char*);
    size_t size = sizeof(specifications_registry) / el_size;
    for (int i = 0; i < size; i++) {
        if (what.compare(specifications_registry[i]) == 0) {
            return true;
        }
    }
    return false;
}

static int isFunction(const std::string& what) {
    size_t el_size = sizeof(char*);
    size_t size = sizeof(functions_registry) / el_size;
    for (int i = 0; i < size; i++) {
        if (what.compare(functions_registry[i]) == 0) {
            return i;
        }
    }
    return -1;
}

static Token makeToken(const std::string& token_str) {
    Type type;
    if (token_str == "\n") {
        type = DELIMITER;
    } else if (isParameter(token_str) != -1) {
        type = PARAMETER;
    } else if (isSpecification(token_str)) {
        type = SPECIFICATION;
    } else if (isFunction(token_str) != -1) {
        type = FUNCTION;
    } else {
        throw Exception("Interpreter: invalid token");
    }
    Token token(
        type,
        isParameter(token_str),
        isSpecification(token_str),
        isFunction(token_str)
    );
    return token;
}

static void checkFunctions(const Token& first, int funcs) {
    if ((first.type != FUNCTION) || (funcs != 1)) {
        throw Exception("Interpreter: function is missed "
                        "/ it's in the incorrect position "
                        "/ there are too many functions "
                        "for one command.");
    }
}

static bool searchId(int id, const int* array, int size) {
    for (int i = 0; i < size; i++) {
        if (array[i] == id) {
            return true;
        }
    }
    return false;
}

static void checkById(int id, int params, int specs) {
    bool ok = false;
    if ((params == 2) && (specs == 0)) {
        int size = sizeof(two_parameter_functions) / sizeof(int);
        ok = searchId(id, two_parameter_functions, size);
    } else if ((params == 1) && (specs == 0)) {
        int size = sizeof(one_parameter_functions) / sizeof(int);
        ok = searchId(id, one_parameter_functions, size);
    } else if ((params == 0) && (specs == 1)) {
        int size = sizeof(spec_functions) / sizeof(int);
        ok = searchId(id, spec_functions, size);
    } else if ((params == 0) && (specs == 0)) {
        int size = sizeof(non_argument_functions) / sizeof(int);
        ok = searchId(id, non_argument_functions, size);
    }
    if (!ok) {
        throw Exception("Interpreter: invalid arguments of function");
    }
}

static Instruction makeInstruction(
    int params,
    int specs,
    const Tokens& tokens_group
) {
    Token function = tokens_group[0];
    Token p1(PARAMETER);
    Token p2(PARAMETER);
    Token spec(SPECIFICATION);
    if (params == 2) {
        p1 = tokens_group[1];
        p2 = tokens_group[2];
    } else if (params == 1) {
        p1 = tokens_group[1];
    } else if (specs == 1) {
        spec = tokens_group[1];
    }
    Instruction instruction(function, p1, p2, spec);
    return instruction;
}

Token::Token(
    Type type,
    int parameter,
    bool spec,
    int function_id
)
    : type(type)
    , parameter(parameter)
    , spec(spec)
    , function_id(function_id)
{
}

Instruction::Instruction(
    Token function,
    Token p1,
    Token p2,
    Token spec
)
    : function(function)
    , p1(p1)
    , p2(p2)
    , spec(spec)
{
}

PackedInstruction::PackedInstruction(
    int function_id,
    int p1,
    int p2,
    bool spec
)
    : function_id(function_id)
    , p1(p1)
    , p2(p2)
    , spec(spec)
{
}

BytecodePtr Bytecode::make(const std::string& source) {
    BytecodePtr bytecode(new Bytecode);
    bytecode->generateBytecode(source);
    return bytecode;
}

Bytecode::Bytecode() {
}

PackedInstruction Bytecode::getInstruction(int index) const {
    bool less = index < 0;
    bool greater = index >= bytecode_.size();
    if (less || greater) {
        throw Exception("Bytecode: invalid index of instruction.");
    }
    return bytecode_[index];
}

void Bytecode::generateBytecode(const std::string& source) {
    Tokens tokens = lexer(source);
    Instructions ast = parser(tokens);
    compile(ast);
}

Tokens Bytecode::lexer(const std::string& source) const {
    Strings lines;
    split(source, '\n', lines);
    Strings tokens_str;
    for (int i = 0; i < lines.size(); i++) {
        split(lines[i], ' ', tokens_str);
        tokens_str.push_back("\n");
    }
    Tokens result;
    for (int i = 0; i < tokens_str.size(); i++) {
        result.push_back(makeToken(tokens_str[i]));
    }
    return result;
}

Instructions Bytecode::parser(const Tokens& tokens) const {
    Tokens tokens_group;
    // Abstract syntax tree.
    Instructions ast;
    int funcs = 0, params = 0, specs = 0;
    for (int i = 0; i < tokens.size(); i++) {
        if (tokens[i].type == DELIMITER) {
            checkFunctions(tokens_group[0], funcs);
            checkById(tokens_group[0].function_id, params, specs);
            Instruction inst =
                makeInstruction(params, specs, tokens_group);
            ast.push_back(inst);
            funcs = 0, params = 0, specs = 0;
            tokens_group.clear();
        } else {
            if (tokens[i].type == FUNCTION) {
                funcs++;
            } else if (tokens[i].type == PARAMETER) {
                params++;
            } else {
                specs++;
            }
            tokens_group.push_back(tokens[i]);
        }
    }
    return ast;
}

void Bytecode::compile(const Instructions& instructions) {
    for (int i = 0; i < instructions.size(); i++) {
        int func_id = instructions[i].function.function_id;
        int p1 = instructions[i].p1.parameter;
        int p2 = instructions[i].p2.parameter;
        bool spec = instructions[i].spec.spec;
        PackedInstruction packed_inst(func_id, p1, p2, spec);
        bytecode_.push_back(packed_inst);
    }
}

}
<commit_msg>Bytecode: comment future changer methods<commit_after>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#include "Bytecode.hpp"

namespace Implementation {

// These two static arrays describe language: all possible
// functions ans specifications.

static const char* const specifications_registry[] = {
    "r"
};

static const char* const functions_registry[] = {
    "eat", "go", "clon", "str", "left", "right", "back", "turn",
    "jg", "jl", "j", "je", /*"jfe", "jw", "jfw",
    "jb", "jfb"*/
};

// These four static arrays contain IDs of functions from
// functions_registry.

static const int two_parameter_functions[] = {
    8, 9
};

static const int one_parameter_functions[] = {
    0, 1, 3, 4, 5, 10, 11, 12, 13, 14, 15, 16
};

static const int spec_functions[] = {
    0, 1, 7
};

static const int non_argument_functions[] = {
    0, 1, 2, 3, 4, 5, 6
};

static void split(
    const std::string& str,
    char delimiter,
    Strings items
) {
    std::stringstream s_stream(str);
    std::string item;
    while (std::getline(s_stream, item, delimiter)) {
        if (!item.empty()) {
            items.push_back(item);
        }
    }
}

static int isParameter(const std::string& what) {
    bool is_parameter = true;
    for (int i = 0; i < what.size(); i++) {
        if (!isdigit(what[i])) {
            is_parameter = false;
        }
    }
    return (is_parameter) ? atoi(what.c_str()) : -1;
}

static bool isSpecification(const std::string& what) {
    size_t el_size = sizeof(char*);
    size_t size = sizeof(specifications_registry) / el_size;
    for (int i = 0; i < size; i++) {
        if (what.compare(specifications_registry[i]) == 0) {
            return true;
        }
    }
    return false;
}

static int isFunction(const std::string& what) {
    size_t el_size = sizeof(char*);
    size_t size = sizeof(functions_registry) / el_size;
    for (int i = 0; i < size; i++) {
        if (what.compare(functions_registry[i]) == 0) {
            return i;
        }
    }
    return -1;
}

static Token makeToken(const std::string& token_str) {
    Type type;
    if (token_str == "\n") {
        type = DELIMITER;
    } else if (isParameter(token_str) != -1) {
        type = PARAMETER;
    } else if (isSpecification(token_str)) {
        type = SPECIFICATION;
    } else if (isFunction(token_str) != -1) {
        type = FUNCTION;
    } else {
        throw Exception("Interpreter: invalid token");
    }
    Token token(
        type,
        isParameter(token_str),
        isSpecification(token_str),
        isFunction(token_str)
    );
    return token;
}

static void checkFunctions(const Token& first, int funcs) {
    if ((first.type != FUNCTION) || (funcs != 1)) {
        throw Exception("Interpreter: function is missed "
                        "/ it's in the incorrect position "
                        "/ there are too many functions "
                        "for one command.");
    }
}

static bool searchId(int id, const int* array, int size) {
    for (int i = 0; i < size; i++) {
        if (array[i] == id) {
            return true;
        }
    }
    return false;
}

static void checkById(int id, int params, int specs) {
    bool ok = false;
    if ((params == 2) && (specs == 0)) {
        int size = sizeof(two_parameter_functions) / sizeof(int);
        ok = searchId(id, two_parameter_functions, size);
    } else if ((params == 1) && (specs == 0)) {
        int size = sizeof(one_parameter_functions) / sizeof(int);
        ok = searchId(id, one_parameter_functions, size);
    } else if ((params == 0) && (specs == 1)) {
        int size = sizeof(spec_functions) / sizeof(int);
        ok = searchId(id, spec_functions, size);
    } else if ((params == 0) && (specs == 0)) {
        int size = sizeof(non_argument_functions) / sizeof(int);
        ok = searchId(id, non_argument_functions, size);
    }
    if (!ok) {
        throw Exception("Interpreter: invalid arguments of function");
    }
}

static Instruction makeInstruction(
    int params,
    int specs,
    const Tokens& tokens_group
) {
    Token function = tokens_group[0];
    Token p1(PARAMETER);
    Token p2(PARAMETER);
    Token spec(SPECIFICATION);
    if (params == 2) {
        p1 = tokens_group[1];
        p2 = tokens_group[2];
    } else if (params == 1) {
        p1 = tokens_group[1];
    } else if (specs == 1) {
        spec = tokens_group[1];
    }
    Instruction instruction(function, p1, p2, spec);
    return instruction;
}

Token::Token(
    Type type,
    int parameter,
    bool spec,
    int function_id
)
    : type(type)
    , parameter(parameter)
    , spec(spec)
    , function_id(function_id)
{
}

Instruction::Instruction(
    Token function,
    Token p1,
    Token p2,
    Token spec
)
    : function(function)
    , p1(p1)
    , p2(p2)
    , spec(spec)
{
}

PackedInstruction::PackedInstruction(
    int function_id,
    int p1,
    int p2,
    bool spec
)
    : function_id(function_id)
    , p1(p1)
    , p2(p2)
    , spec(spec)
{
}

BytecodePtr Bytecode::make(const std::string& source) {
    BytecodePtr bytecode(new Bytecode);
    bytecode->generateBytecode(source);
    return bytecode;
}

Bytecode::Bytecode() {
}

PackedInstruction Bytecode::getInstruction(int index) const {
    bool less = index < 0;
    bool greater = index >= bytecode_.size();
    if (less || greater) {
        throw Exception("Bytecode: invalid index of instruction.");
    }
    return bytecode_[index];
}

void Bytecode::generateBytecode(const std::string& source) {
    Tokens tokens = lexer(source);
    Instructions ast = parser(tokens);
    compile(ast);
}

Tokens Bytecode::lexer(const std::string& source) const {
    Strings lines;
    split(source, '\n', lines);
    Strings tokens_str;
    for (int i = 0; i < lines.size(); i++) {
        split(lines[i], ' ', tokens_str);
        tokens_str.push_back("\n");
    }
    Tokens result;
    for (int i = 0; i < tokens_str.size(); i++) {
        result.push_back(makeToken(tokens_str[i]));
    }
    return result;
}

Instructions Bytecode::parser(const Tokens& tokens) const {
    Tokens tokens_group;
    // Abstract syntax tree.
    Instructions ast;
    int funcs = 0, params = 0, specs = 0;
    for (int i = 0; i < tokens.size(); i++) {
        if (tokens[i].type == DELIMITER) {
            checkFunctions(tokens_group[0], funcs);
            checkById(tokens_group[0].function_id, params, specs);
            Instruction inst =
                makeInstruction(params, specs, tokens_group);
            ast.push_back(inst);
            funcs = 0, params = 0, specs = 0;
            tokens_group.clear();
        } else {
            if (tokens[i].type == FUNCTION) {
                funcs++;
            } else if (tokens[i].type == PARAMETER) {
                params++;
            } else {
                specs++;
            }
            tokens_group.push_back(tokens[i]);
        }
    }
    return ast;
}

void Bytecode::compile(const Instructions& instructions) {
    for (int i = 0; i < instructions.size(); i++) {
        int func_id = instructions[i].function.function_id;
        int p1 = instructions[i].p1.parameter;
        int p2 = instructions[i].p2.parameter;
        bool spec = instructions[i].spec.spec;
        PackedInstruction packed_inst(func_id, p1, p2, spec);
        bytecode_.push_back(packed_inst);
    }
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 David Wicks
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ImagePacker.h"
#include "cinder/Text.h"
#include "cinder/ip/Trim.h"
#include "cinder/ip/Fill.h"
#include "cinder/ip/Premultiply.h"

using namespace ci;
using namespace std;
using namespace pockets;

ImagePacker::ImagePacker()
{}

ImagePacker::~ImagePacker()
{}

ImagePacker::ImageDataRef ImagePacker::addImage( const std::string &id, ci::Surface surface, bool trim_alpha )
{
  if( trim_alpha )
  {
    Area bounds = ip::findNonTransparentArea( surface, surface.getBounds() );
    assert( bounds.getWidth() <= surface.getWidth() );
    assert( bounds.getHeight() <= surface.getHeight() );
    Surface trimmed_copy( bounds.getWidth(), bounds.getHeight(), true, SurfaceChannelOrder::RGBA );
    trimmed_copy.copyFrom( surface, bounds, -bounds.getUL() );
    surface = trimmed_copy;
  }
  mImages.push_back( make_shared<ImageData>( surface, id ) );
  return mImages.back();
}

vector<ImagePacker::ImageDataRef> ImagePacker::addGlyphs( const ci::Font &font, const string &glyphs, const string &id_prefix, bool trim_alpha )
{
  vector<ImageDataRef> ret;
  for( const char glyph : glyphs )
  {
    ret.push_back( addString( id_prefix + toString<char>(glyph), font, toString<char>(glyph), trim_alpha ));
  }
  return ret;
}

ImagePacker::ImageDataRef ImagePacker::addString( const string &id, const Font &font, const string &str, bool trim_alpha )
{
  TextLayout layout;
  layout.clear( ColorA( 0, 0, 0, 0 ) );
  layout.setFont( font );
  layout.setColor( ColorA::white() );
  auto lines = split( str, "\n" );
  for( auto &line : lines ) {
    layout.addLine( line );
  }
  Surface image = layout.render( true, false );
  return addImage( id, image, trim_alpha );
}

JsonTree ImagePacker::surfaceDescription()
{
  JsonTree description;
  JsonTree metaData = JsonTree::makeObject("meta");
  metaData.pushBack( JsonTree("created_by", "David Wicks' pockets::ImagePacker") );
  metaData.pushBack( JsonTree("width", mWidth ) );
  metaData.pushBack( JsonTree("height", mHeight ) );
  description.pushBack( metaData );

  JsonTree sprites = JsonTree::makeArray("sprites");
  for( ImageDataRef sprite : mImages )
  {
    sprites.pushBack( sprite->toJson() );
  }
  description.pushBack( sprites );

  return description;
}

Surface ImagePacker::packedSurface( bool premultiply )
{
  Surface output( mWidth, mHeight, true, SurfaceChannelOrder::RGBA );
  ip::fill( &output, ColorA( 0, 0, 0, 0 ) );
  for( ImageDataRef sprite : mImages )
  {
    output.copyFrom( sprite->getSurface(), sprite->getBounds(), sprite->getLoc() );
  }
  // XCode premultiplies anything going to an iOS device (ignores flag telling it not to)
  // Double-premultiplication makes everything have dark edges
  // So we'll just premultiply on the client side if the graphics aren't already
  if( premultiply )
  {
    ip::premultiply( &output );
  }
  return output;
}

void ImagePacker::calculatePositions( const ci::Vec2i &padding, const int width )
{
  //  auto rev_area_compare = []( const ImageData &lhs, const ImageData &rhs )
  //  {
  //    return lhs.getBounds().calcArea() > rhs.getBounds().calcArea();
  //  };
  auto rev_height_compare = []( const ImageDataRef &lhs, const ImageDataRef &rhs )
  {
    return lhs->getBounds().getHeight() > rhs->getBounds().getHeight();
  };
  sort( mImages.begin(), mImages.end(), rev_height_compare );
  Vec2i loc( 0, 0 );
  int bottom_y = 0;
  for( ImageDataRef sprite : mImages )
  {
    if( loc.x + sprite->getBounds().getWidth() > width )
    {
      loc.y = bottom_y + padding.y;
      loc.x = 0;
    }
    sprite->setLoc( loc );
    loc.x += sprite->getBounds().getWidth() + padding.x;
    bottom_y = math<int>::max( sprite->getBounds().getHeight() + loc.y, bottom_y );
  }
  mWidth = width;
  mHeight = math<int>::max( bottom_y, width );
}

void ImagePacker::calculatePositionsScanline( const Vec2i &padding, const int width )
{
  // auto rev_area_compare = []( const ImageDataRef &lhs, const ImageDataRef &rhs )
  // {
  //   return lhs->getBounds().calcArea() > rhs->getBounds().calcArea();
  // }
  auto rev_height_compare = []( const ImageDataRef &lhs, const ImageDataRef &rhs )
  {
    return lhs->getBounds().getHeight() > rhs->getBounds().getHeight();
  };
  sort( mImages.begin(), mImages.end(), rev_height_compare );
  int bottom_y = 0;
  // place largest image at top-left
  mImages.at( 0 )->setLoc( padding );
  for( int i = 1; i < mImages.size(); ++i )
  { // for each following image, start at top-left and look on each
    // pixel row for a potential free space
    Vec2i loc{ padding };
    auto img = mImages.at( i );
    bool placed = false;
    while ( !placed )
    {
      for( int j = 0; j < i; ++j )
      { // check whether we're inside the bounds of any previously placed image (including padding)
        auto bounds = mImages.at( j )->getPlacedBounds().inflated( padding );
        if( bounds.contains( loc ) )
        { // jump to right edge of image
          loc.x = bounds.getX2();
        }
      }

      if( loc.x + img->getWidth() < width - padding.x )
      { // we fit on the page, though we may still overlap other images
        // tentatively set the image location here
        img->setLoc( loc );
        placed = true;
        // shrink potential bounds by one, since sharing a vertex counts as Rectf intersecting
        auto potential_bounds = img->getPlacedBounds().inflated( { -1, -1 } );
        for( int j = 0; j < i; ++j )
        { // check that the placed boundaries don't overlap any other placed image
          auto bounds = mImages.at( j )->getPlacedBounds().inflated( padding );
          if( potential_bounds.intersects( bounds ) )
          { // a collision was found, so we'll continue the loop
            placed = false;
          }
        }
        bottom_y = math<int>::max( img->getBounds().getHeight() + loc.y, bottom_y );
      }
      // move to next row of pixels for continued evaluation
      loc.x = padding.x;
      loc.y += 1;

      // if we would never fit on the page, we need to issue a warning
      if( img->getWidth() > width ) {
        app::console() << "WARNING: Source image too wide. Omitting " << img->getId() << endl;
        break;
      }
    }
  }
  mWidth = width;
  mHeight = math<int>::max( bottom_y, width );
}

<commit_msg>Account for padding in bailout.<commit_after>/*
 * Copyright (c) 2013 David Wicks
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ImagePacker.h"
#include "cinder/Text.h"
#include "cinder/ip/Trim.h"
#include "cinder/ip/Fill.h"
#include "cinder/ip/Premultiply.h"

using namespace ci;
using namespace std;
using namespace pockets;

ImagePacker::ImagePacker()
{}

ImagePacker::~ImagePacker()
{}

ImagePacker::ImageDataRef ImagePacker::addImage( const std::string &id, ci::Surface surface, bool trim_alpha )
{
  if( trim_alpha )
  {
    Area bounds = ip::findNonTransparentArea( surface, surface.getBounds() );
    assert( bounds.getWidth() <= surface.getWidth() );
    assert( bounds.getHeight() <= surface.getHeight() );
    Surface trimmed_copy( bounds.getWidth(), bounds.getHeight(), true, SurfaceChannelOrder::RGBA );
    trimmed_copy.copyFrom( surface, bounds, -bounds.getUL() );
    surface = trimmed_copy;
  }
  mImages.push_back( make_shared<ImageData>( surface, id ) );
  return mImages.back();
}

vector<ImagePacker::ImageDataRef> ImagePacker::addGlyphs( const ci::Font &font, const string &glyphs, const string &id_prefix, bool trim_alpha )
{
  vector<ImageDataRef> ret;
  for( const char glyph : glyphs )
  {
    ret.push_back( addString( id_prefix + toString<char>(glyph), font, toString<char>(glyph), trim_alpha ));
  }
  return ret;
}

ImagePacker::ImageDataRef ImagePacker::addString( const string &id, const Font &font, const string &str, bool trim_alpha )
{
  TextLayout layout;
  layout.clear( ColorA( 0, 0, 0, 0 ) );
  layout.setFont( font );
  layout.setColor( ColorA::white() );
  auto lines = split( str, "\n" );
  for( auto &line : lines ) {
    layout.addLine( line );
  }
  Surface image = layout.render( true, false );
  return addImage( id, image, trim_alpha );
}

JsonTree ImagePacker::surfaceDescription()
{
  JsonTree description;
  JsonTree metaData = JsonTree::makeObject("meta");
  metaData.pushBack( JsonTree("created_by", "David Wicks' pockets::ImagePacker") );
  metaData.pushBack( JsonTree("width", mWidth ) );
  metaData.pushBack( JsonTree("height", mHeight ) );
  description.pushBack( metaData );

  JsonTree sprites = JsonTree::makeArray("sprites");
  for( ImageDataRef sprite : mImages )
  {
    sprites.pushBack( sprite->toJson() );
  }
  description.pushBack( sprites );

  return description;
}

Surface ImagePacker::packedSurface( bool premultiply )
{
  Surface output( mWidth, mHeight, true, SurfaceChannelOrder::RGBA );
  ip::fill( &output, ColorA( 0, 0, 0, 0 ) );
  for( ImageDataRef sprite : mImages )
  {
    output.copyFrom( sprite->getSurface(), sprite->getBounds(), sprite->getLoc() );
  }
  // XCode premultiplies anything going to an iOS device (ignores flag telling it not to)
  // Double-premultiplication makes everything have dark edges
  // So we'll just premultiply on the client side if the graphics aren't already
  if( premultiply )
  {
    ip::premultiply( &output );
  }
  return output;
}

void ImagePacker::calculatePositions( const ci::Vec2i &padding, const int width )
{
  //  auto rev_area_compare = []( const ImageData &lhs, const ImageData &rhs )
  //  {
  //    return lhs.getBounds().calcArea() > rhs.getBounds().calcArea();
  //  };
  auto rev_height_compare = []( const ImageDataRef &lhs, const ImageDataRef &rhs )
  {
    return lhs->getBounds().getHeight() > rhs->getBounds().getHeight();
  };
  sort( mImages.begin(), mImages.end(), rev_height_compare );
  Vec2i loc( 0, 0 );
  int bottom_y = 0;
  for( ImageDataRef sprite : mImages )
  {
    if( loc.x + sprite->getBounds().getWidth() > width )
    {
      loc.y = bottom_y + padding.y;
      loc.x = 0;
    }
    sprite->setLoc( loc );
    loc.x += sprite->getBounds().getWidth() + padding.x;
    bottom_y = math<int>::max( sprite->getBounds().getHeight() + loc.y, bottom_y );
  }
  mWidth = width;
  mHeight = math<int>::max( bottom_y, width );
}

void ImagePacker::calculatePositionsScanline( const Vec2i &padding, const int width )
{
  // auto rev_area_compare = []( const ImageDataRef &lhs, const ImageDataRef &rhs )
  // {
  //   return lhs->getBounds().calcArea() > rhs->getBounds().calcArea();
  // }
  auto rev_height_compare = []( const ImageDataRef &lhs, const ImageDataRef &rhs )
  {
    return lhs->getBounds().getHeight() > rhs->getBounds().getHeight();
  };
  sort( mImages.begin(), mImages.end(), rev_height_compare );
  int bottom_y = 0;
  // place largest image at top-left
  mImages.at( 0 )->setLoc( padding );

  for( int i = 1; i < mImages.size(); ++i )
  { // for each following image, start at top-left and look on each
    // pixel row for a potential free space
    Vec2i loc{ padding };
    auto img = mImages.at( i );
    bool placed = false;
    while ( !placed )
    {
      for( int j = 0; j < i; ++j )
      { // check whether we're inside the bounds of any previously placed image (including padding)
        auto bounds = mImages.at( j )->getPlacedBounds().inflated( padding );
        if( bounds.contains( loc ) )
        { // jump to right edge of image
          loc.x = bounds.getX2();
        }
      }

      if( loc.x + img->getWidth() < width - padding.x )
      { // we fit on the page, though we may still overlap other images
        // tentatively set the image location here
        img->setLoc( loc );
        placed = true;
        // shrink potential bounds by one, since sharing a vertex counts as Rectf intersecting
        auto potential_bounds = img->getPlacedBounds().inflated( { -1, -1 } );
        for( int j = 0; j < i; ++j )
        { // check that the placed boundaries don't overlap any other placed image
          auto bounds = mImages.at( j )->getPlacedBounds().inflated( padding );
          if( potential_bounds.intersects( bounds ) )
          { // a collision was found, so we'll continue the loop
            placed = false;
          }
        }
        bottom_y = math<int>::max( img->getBounds().getHeight() + loc.y, bottom_y );
      }
      // move to next row of pixels for continued evaluation
      loc.x = padding.x;
      loc.y += 1;

      // if we would never fit on the page, we need to issue a warning
      if( img->getWidth() + padding.x > width ) {
        app::console() << "WARNING: Source image too wide. Omitting " << img->getId() << endl;
        break;
      }
    }
  }
  mWidth = width;
  mHeight = math<int>::max( bottom_y, width );
}

<|endoftext|>


<commit_before>///
/// @file   PreSieve.cpp
/// @brief  Pre-sieve multiples of small primes to speed up the
///         sieve of Eratosthenes.
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/PreSieve.hpp>
#include <primesieve/EratSmall.hpp>
#include <primesieve/primesieve_error.hpp>

#include <stdint.h>
#include <cstring>

namespace primesieve {

const uint_t PreSieve::primes_[10] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };

/// PreSieve multiples of small primes <= limit.
/// @pre limit >= 11 && <= 23
///
PreSieve::PreSieve(int limit)
{
  // limit <= 23 prevents 32-bit overflows
  if (limit < 11 || limit > 23)
    throw primesieve_error("PreSieve: limit must be >= 11 && <= 23");
  limit_ = limit;
  primeProduct_ = 1;
  for (int i = 0; primes_[i] <= limit_; i++)
    primeProduct_ *= primes_[i];
  size_ = primeProduct_ / NUMBERS_PER_BYTE;
  preSieved_ = new byte_t[size_];
  init();
}

PreSieve::~PreSieve()
{
  delete[] preSieved_;
}

/// Cross-off the multiples of small primes <= limit_
/// in the preSieved_ array.
///
void PreSieve::init()
{
  std::memset(preSieved_, 0xff, size_);
  uint_t stop = primeProduct_ * 2;
  EratSmall eratSmall(stop, size_, limit_);

  for (int i = 3; primes_[i] <= limit_; i++)
    eratSmall.addSievingPrime(primes_[i], primeProduct_);

  eratSmall.crossOff(preSieved_, &preSieved_[size_]);
}

/// Pre-sieve the multiples of small primes <= limit_
/// in the sieve array.
///
void PreSieve::doIt(byte_t* sieve, uint_t sieveSize, uint64_t segmentLow) const
{
  // map segmentLow to the preSieved_ array
  uint_t remainder = static_cast<uint_t>(segmentLow % primeProduct_);
  uint_t index = remainder / NUMBERS_PER_BYTE;
  uint_t sizeLeft = size_ - index;

  if (sieveSize <= sizeLeft)
    std::memcpy(sieve, &preSieved_[index], sieveSize);
  else {
    // copy the last remaining bytes at the end of preSieved_
    // to the beginning of the sieve array
    std::memcpy(sieve, &preSieved_[index], sizeLeft);
    // restart copying at the beginning of preSieved_
    for (index = sizeLeft; index + size_ < sieveSize; index += size_)
      std::memcpy(&sieve[index], preSieved_, size_);
    std::memcpy(&sieve[index], preSieved_, sieveSize - index);
  }
}

} // namespace primesieve
<commit_msg>Refactoring<commit_after>///
/// @file   PreSieve.cpp
/// @brief  Pre-sieve multiples of small primes to speed up the
///         sieve of Eratosthenes.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/PreSieve.hpp>
#include <primesieve/EratSmall.hpp>
#include <primesieve/primesieve_error.hpp>

#include <stdint.h>
#include <cstring>

namespace primesieve {

const uint_t PreSieve::primes_[10] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };

/// PreSieve multiples of small primes <= limit.
/// @pre limit >= 11 && <= 23
///
PreSieve::PreSieve(int limit)
{
  // limit <= 23 prevents 32-bit overflows
  if (limit < 11 || limit > 23)
    throw primesieve_error("PreSieve: limit must be >= 11 && <= 23");
  limit_ = limit;
  init();
}

PreSieve::~PreSieve()
{
  delete[] preSieved_;
}

/// Cross-off the multiples of small primes <= limit_
/// in the preSieved_ array.
///
void PreSieve::init()
{
  primeProduct_ = 1;
  for (int i = 0; primes_[i] <= limit_; i++)
    primeProduct_ *= primes_[i];

  size_ = primeProduct_ / NUMBERS_PER_BYTE;
  preSieved_ = new byte_t[size_];
  std::memset(preSieved_, 0xff, size_);

  uint_t stop = primeProduct_ * 2;
  EratSmall eratSmall(stop, size_, limit_);

  for (int i = 3; primes_[i] <= limit_; i++)
    eratSmall.addSievingPrime(primes_[i], primeProduct_);
  eratSmall.crossOff(preSieved_, &preSieved_[size_]);
}

/// Pre-sieve the multiples of small primes <= limit_
/// in the sieve array.
///
void PreSieve::doIt(byte_t* sieve, uint_t sieveSize, uint64_t segmentLow) const
{
  // map segmentLow to the preSieved_ array
  uint_t remainder = static_cast<uint_t>(segmentLow % primeProduct_);
  uint_t index = remainder / NUMBERS_PER_BYTE;
  uint_t sizeLeft = size_ - index;

  if (sieveSize <= sizeLeft)
    std::memcpy(sieve, &preSieved_[index], sieveSize);
  else {
    // copy the last remaining bytes at the end of preSieved_
    // to the beginning of the sieve array
    std::memcpy(sieve, &preSieved_[index], sizeLeft);
    // restart copying at the beginning of preSieved_
    for (index = sizeLeft; index + size_ < sieveSize; index += size_)
      std::memcpy(&sieve[index], preSieved_, size_);
    std::memcpy(&sieve[index], preSieved_, sieveSize - index);
  }
}

} // namespace primesieve
<|endoftext|>


<commit_before>
/**
 * Implementation of a string rope.
 *
 * @author Jean-Claude Paquin
 **/

#include "str_rope.h"
#include <sstream>

// Define rope_node helper struct

rope_node::rope_node() {
    memset(&data, 0, sizeof(data));
}

rope_node::rope_node(rope_node& other) : is_leaf(other.is_leaf), actual_size(other.actual_size) {
    if(is_leaf) {
        str.release();
        str = std::make_unique<const std::string>(*other.str);
    } else {
        data.len = other.data.len;

        if(other.data.left) {
            if(other.data.left->is_leaf) {
                data.left = other.data.left;
            } else {
                data.left = std::make_shared<rope_node>(*other.data.left);
            }
        }

        if(other.data.right) {
            if(other.data.right && other.data.right->is_leaf) {
                data.right = other.data.right;
            } else {
                data.right = std::make_shared<rope_node>(*other.data.right);
            }
        }
    }
}

rope_node::rope_node(const std::string& str) : is_leaf(true), actual_size(str.length()) {
    this->str.release();
    this->str = std::make_unique<const std::string>(str);
}

void rope_node::set_left(std::shared_ptr<rope_node> left) {
    if(is_leaf) return;

    if(data.left) {
        actual_size -= data.left->actual_size;
    }
    actual_size += left->actual_size;
    data.len = left->actual_size;
    data.left = left;
}

void rope_node::set_right(std::shared_ptr<rope_node> right) {
    if(is_leaf) return;

    if(data.right) {
        actual_size -= data.right->actual_size;
    }
    actual_size += right->actual_size;
    data.right = right;
}

void rope_node::update_size() {
    if(this->is_leaf) {
        actual_size = str->length();
    } else {
        actual_size = 0;

        if(data.left) {
            data.left->update_size();
            actual_size += data.left->actual_size;
        }

        if(data.right) {
            if(data.right != data.left)
                data.right->update_size();
            actual_size += data.right->actual_size;
        }
    }
}

std::unique_ptr<std::string> rope_node::to_string() const {
    if(is_leaf) {
        return std::make_unique<std::string>(*str);
    } else {
        std::ostringstream *stream = new std::ostringstream();

        if(data.left)
            data.left->to_string(*stream);
        if(data.right)
            data.right->to_string(*stream);

        std::unique_ptr<std::string> ret = std::make_unique<std::string>(stream->str());
        delete stream;

        return std::move(ret);
    }
}

void rope_node::to_string(std::ostringstream& stream) {
    if(is_leaf) {
        stream << *str;
    } else {
        if(data.left)
            data.left->to_string(stream);
        if(data.right)
            data.right->to_string(stream);
    }
}

// End of rope_node definitions

// Define str_rope

str_rope::str_rope() {
    root = std::make_shared<rope_node>();
}

str_rope::str_rope(const std::string &str) {
    root = std::make_shared<rope_node>();
    auto leaf = std::make_shared<rope_node>(str);

    root->set_left(leaf);
}

str_rope::str_rope(const str_rope &other) {
    root = std::make_shared<rope_node>(*other.root);
}
<commit_msg>Added some more simple methods<commit_after>
/**
 * Implementation of a string rope.
 *
 * @author Jean-Claude Paquin
 **/

#include "str_rope.h"
#include <sstream>

// Define rope_node helper struct

rope_node::rope_node() {
    memset(&data, 0, sizeof(data));
}

rope_node::rope_node(rope_node& other) : is_leaf(other.is_leaf), actual_size(other.actual_size) {
    if(is_leaf) {
        str.release();
        str = std::make_unique<const std::string>(*other.str);
    } else {
        data.len = other.data.len;

        if(other.data.left) {
            if(other.data.left->is_leaf) {
                data.left = other.data.left;
            } else {
                data.left = std::make_shared<rope_node>(*other.data.left);
            }
        }

        if(other.data.right) {
            if(other.data.right && other.data.right->is_leaf) {
                data.right = other.data.right;
            } else {
                data.right = std::make_shared<rope_node>(*other.data.right);
            }
        }
    }
}

rope_node::rope_node(const std::string& str) : is_leaf(true), actual_size(str.length()) {
    this->str.release();
    this->str = std::make_unique<const std::string>(str);
}

void rope_node::set_left(std::shared_ptr<rope_node> left) {
    if(is_leaf) return;

    if(data.left) {
        actual_size -= data.left->actual_size;
    }
    actual_size += left->actual_size;
    data.len = left->actual_size;
    data.left = left;
}

void rope_node::set_right(std::shared_ptr<rope_node> right) {
    if(is_leaf) return;

    if(data.right) {
        actual_size -= data.right->actual_size;
    }
    actual_size += right->actual_size;
    data.right = right;
}

void rope_node::update_size() {
    if(this->is_leaf) {
        actual_size = str->length();
    } else {
        actual_size = 0;

        if(data.left) {
            data.left->update_size();
            actual_size += data.left->actual_size;
        }

        if(data.right) {
            if(data.right != data.left)
                data.right->update_size();
            actual_size += data.right->actual_size;
        }
    }
}

std::unique_ptr<std::string> rope_node::to_string() const {
    if(is_leaf) {
        return std::make_unique<std::string>(*str);
    } else {
        std::ostringstream *stream = new std::ostringstream();

        if(data.left)
            data.left->to_string(*stream);
        if(data.right)
            data.right->to_string(*stream);

        std::unique_ptr<std::string> ret = std::make_unique<std::string>(stream->str());
        delete stream;

        return std::move(ret);
    }
}

void rope_node::to_string(std::ostringstream& stream) {
    if(is_leaf) {
        stream << *str;
    } else {
        if(data.left)
            data.left->to_string(stream);
        if(data.right)
            data.right->to_string(stream);
    }
}

// End of rope_node definitions

// Define str_rope

str_rope::str_rope() {
    root = std::make_shared<rope_node>();
}

str_rope::str_rope(const std::string &str) {
    root = std::make_shared<rope_node>();
    auto leaf = std::make_shared<rope_node>(str);

    root->set_left(leaf);
}

str_rope::str_rope(const str_rope &other) {
    root = std::make_shared<rope_node>(*other.root);
}

std::unique_ptr<std::string> str_rope::to_string() const {
    return root->to_string();
}

size_t str_rope::get_length() const {
    return root->actual_size;
}

<|endoftext|>


<commit_before>//
// Copyright (C) 1997 Shigeru Chiba
// Copyright (C) 2004 Stefan Seefeld
// All rights reserved.
// Licensed to the public under the terms of the GNU LGPL (>= 2),
// see the file COPYING for details.
//
#ifndef Synopsis_PTree_Encoding_hh_
#define Synopsis_PTree_Encoding_hh_

#include <string>
#include <iostream>

namespace Synopsis
{
namespace PTree
{

class Node;
class Atom;

//. An Encoding encodes C++ (qualified) names and types. These names
//. are not normalized, as that requires symbol lookup and type analysis.
//.
//. 'b' boolean
//. 'c' char
//. 'w' wchar_t
//. 'i' int (signed, unsigned)
//. 's' short (short int)
//. 'l' long (long int)
//. 'j' long long
//. 'f' float
//. 'd' double
//. 'r' long double
//. 'v' void
//.
//. 'T' template class (e.g. Foo<int,char> ==> T[3]Foo[2]ic.  [2] means
//.     the length of "ic".  It doesn't mean the number of template
//.     arguments.
//. 'e' ...
//. '?' no return type.  the return type of constructors
//. '*' non-type template parameter
//.
//. 'S' signed
//. 'U' unsigned
//. 'C' const
//. 'V' volatile
//.
//. 'P' pointer
//. 'R' reference
//. 'A' array (e.g. char[16] ==> A16_c)
//. 'F' function (e.g. char foo(int) ==> Fi_c)
//. 'M' pointer to member (e.g. Type::* ==> M[4]Type)
//.
//. 'Q' qualified class (e.g. X::YY ==> Q[2][1]X[2]YY, ::YY ==> Q[2][0][2]YY)
//.
//. [x] means (0x80 + x)
//. '0' means :: (global scope)
//.
//. Special function names:
//.
//. operator + ==> +
//. operator new[] ==> new[]
//. operator <type> ==> @<encoded type>		cast operator
class Encoding
{
public:
  struct char_traits
  {
    typedef unsigned char  char_type;
    typedef unsigned long  int_type;
    typedef std::streampos pos_type;
    typedef std::streamoff off_type;
    typedef std::mbstate_t state_type;

    static void assign(char_type &c1, const char_type &c2) { c1 = c2;}
    static bool eq(const char_type &c1, const char_type &c2) { return c1 == c2;}
    static bool lt(const char_type &c1, const char_type &c2) { return c1 < c2;}
    static int compare(const char_type *s1, const char_type *s2, std::size_t n) { return memcmp(s1, s2, n);}
    static std::size_t length(const char_type *s) { return strlen((const char *)s);}
    static const char_type *find(const char_type *s, std::size_t n, const char_type &a)
    { return static_cast<const char_type *>(memchr(s, a, n));}
    static char_type *move(char_type *s1, const char_type *s2, std::size_t n)
    { return static_cast<char_type *>(memmove(s1, s2, n));}
    static char_type *copy(char_type *s1, const char_type *s2, std::size_t n)
    { return static_cast<char_type *>(memcpy(s1, s2, n));}
    static char_type *assign(char_type *s, std::size_t n, char_type a)
    { return static_cast<char_type *>(memset(s, a, n));}
    static char_type to_char_type(const int_type &c) { return static_cast<char_type>(c);}
    static int_type to_int_type(const char_type &c) { return static_cast<int_type>(c);}
    static bool eq_int_type(const int_type &c1, const int_type &c2) { return c1 == c2;}
    static int_type eof() { return static_cast<int_type>(EOF);}
    static int_type not_eof(const int_type &c) { return !eq_int_type(c, eof()) ? c : to_int_type(char_type());}
  };

  typedef std::basic_string<unsigned char, char_traits> Code;
  typedef Code::const_iterator iterator;

  class name_iterator;

  static void do_init_static();

  Encoding() {}
  Encoding(const Code &b) : my_buffer(b) {}
  Encoding(const char *b) : my_buffer(b, b + strlen(b)) {}
  Encoding(const char *b, size_t s) : my_buffer(b, b + s) {}
  Encoding(iterator b, iterator e) : my_buffer(b, e) {}
  static Encoding simple_name(PTree::Atom const *name);

  void clear() { my_buffer.clear();}
  bool empty() const { return my_buffer.empty();}
  size_t size() const { return my_buffer.size();}
  iterator begin() const { return my_buffer.begin();}
  iterator end() const { return my_buffer.end();}
  unsigned char front() const { return *begin();}
  unsigned char at(size_t i) const { return my_buffer.at(i);}
  //. return a copy of the underlaying buffer
  //. FIXME: this is a temporary workaround while there are
  //. still places that use raw strings
  const char *copy() const;

  bool operator == (const Encoding &e) const { return my_buffer == e.my_buffer;}
  bool operator == (const std::string &s) const { return my_buffer == (const unsigned char *)s.c_str();}
  bool operator == (const char *s) const { return my_buffer == (const unsigned char *)s;}

  void prepend(unsigned char c) { my_buffer.insert(my_buffer.begin(), c);}
  void prepend(const char *p, size_t s) { my_buffer.insert(0, (const unsigned char *)p, s);}
  void prepend(const Encoding &e) { my_buffer.insert(0, e.my_buffer);}

  void append(unsigned char c) { my_buffer.append(1, c);}
  void append(const char *p, size_t s) { my_buffer.append((const unsigned char *)p, s);}
  void append(const Encoding &e) { my_buffer.append(e.my_buffer);}
  void append_with_length(const char *s, size_t n) { append(0x80 + n); append((const char *)s, n);}
  void append_with_length(const Encoding &e) { append(0x80 + e.size()); append(e);}

  unsigned char pop();
  void pop(size_t n) { my_buffer.erase(my_buffer.begin(), my_buffer.begin() + n);}

  void cv_qualify(const Node *, const Node * = 0);
  void simple_const() { append("Ci", 2);}
  void global_scope();
  void simple_name(const Node *);
  void anonymous();
  void template_(const Node *, const Encoding &);
  void qualified(int);
  void destructor(const Node *);
  void ptr_operator(int);
  void ptr_to_member(const Encoding &, int);
  void cast_operator(const Encoding &);
  void array() { prepend("A_", 2);}
  void array(unsigned long s);
  void function(const Encoding &e) { prepend(e);}
  void recursion(const Encoding &e) { prepend(e);}
  void start_func_args() { append('F');}
  void end_func_args() { append('_');}
  void void_() { append('v');}
  void ellipsis_arg() { append('e');}
  void no_return_type() { append('?');}
  void value_temp_param() { append('*');}

  name_iterator begin_name() const;
  name_iterator end_name() const;
//   name_iterator begin_function_parameters() const;
//   name_iterator end_function_parameters() const;
  Encoding function_return_type() const;

  //. if this Encoding represents a qualified name,
  //. return the name of the outer scope
  Encoding get_scope() const;
  //. if this Encoding represents a qualified name,
  //. return the name of the symbol inside the outer scope,
  //. else return the unmodified name
  Encoding get_symbol() const;
  Encoding get_template_name() const;
  Encoding get_template_arguments() const;

  std::string unmangled() const;

  PTree::Node *make_name();
  PTree::Node *make_qname();
  PTree::Node *make_ptree(PTree::Node *);
  bool is_simple_name() const { return front() >= 0x80;}
  bool is_global_scope() const { return front() == 0x80 && size() == 1;}
  bool is_qualified() const { return front() == 'Q';}
  bool is_function() const { return front() == 'F';}
  bool is_template_id() const { return front() == 'T';}
  PTree::Node *name_to_ptree();

  friend bool operator < (const Encoding &, const Encoding &);
  friend std::ostream &operator << (std::ostream &, const Encoding &);

private:

  //. Advance the iterator to the start of the next token.
  static iterator advance(iterator);
  iterator end_of_scope() const;
  static iterator end_name(iterator);

  Code my_buffer;

public:
  static PTree::Node *bool_t, *char_t, *wchar_t_t, *int_t, *short_t, *long_t,
		 *float_t, *double_t, *void_t;

  static PTree::Node *signed_t, *unsigned_t, *const_t, *volatile_t;

  static PTree::Node *operator_name, *new_operator, *anew_operator,
		 *delete_operator, *adelete_operator;

  static PTree::Node *star, *ampersand, *comma, *dots, *scope, *tilder,
		 *left_paren, *right_paren, *left_bracket, *right_bracket,
		 *left_angle, *right_angle;
};

class Encoding::name_iterator
{
public:
  name_iterator(iterator e, iterator i)
    : my_end(e),
      my_cursor(*i == 'Q' ? i + 2 : i),
      my_component(my_cursor, i == e ? my_cursor : Encoding::advance(my_cursor))
  {
  }
  name_iterator &operator++() { next(); return *this;}
  name_iterator operator++(int) { name_iterator retn(*this); next(); return retn;}
  Encoding const &operator*() const { return my_component;}
  Encoding const *operator->() const { return &my_component;}
  bool operator==(name_iterator const &i) const { return my_cursor == i.my_cursor;}
  bool operator!=(name_iterator const &i) const { return my_cursor != i.my_cursor;}

private:
  void next()
  {
    my_cursor += my_component.size();
    if (my_cursor != my_end)
      my_component = Encoding(my_cursor, Encoding::advance(my_cursor));
  }

  iterator const my_end;
  iterator       my_cursor;
  Encoding       my_component;
};

inline Encoding::name_iterator Encoding::begin_name() const
{
  return name_iterator(end(), begin());
}

inline Encoding::name_iterator Encoding::end_name() const
{
  return name_iterator(end(), end());
}

inline Encoding Encoding::function_return_type() const
{
  assert(is_function());
  // Find the token after the end-of-parameter-list marker ('_')
  iterator b = my_buffer.begin();
  while (*b != '_') ++b;
  iterator e = advance(++b);
  return Encoding(b, e);
}

inline bool operator < (const Encoding &e1, const Encoding &e2)
{
  return e1.my_buffer < e2.my_buffer;
}

inline std::ostream &operator << (std::ostream &os, const Encoding &e)
{
  for (Encoding::iterator i = e.begin();
       i != e.end();
       ++i)
    if(*i < 0x80) os.put(static_cast<char>(*i));
    else os << '[' << static_cast<int>(*i - 0x80) << ']';
  return os;
}

inline unsigned char Encoding::pop()
{
  unsigned char code = my_buffer[0];
  my_buffer.erase(0, 1);
  return code;
}

}
}

#endif
<commit_msg>Add missing #include <cassert><commit_after>//
// Copyright (C) 1997 Shigeru Chiba
// Copyright (C) 2004 Stefan Seefeld
// All rights reserved.
// Licensed to the public under the terms of the GNU LGPL (>= 2),
// see the file COPYING for details.
//
#ifndef Synopsis_PTree_Encoding_hh_
#define Synopsis_PTree_Encoding_hh_

#include <string>
#include <iostream>
#include <cassert>

namespace Synopsis
{
namespace PTree
{

class Node;
class Atom;

//. An Encoding encodes C++ (qualified) names and types. These names
//. are not normalized, as that requires symbol lookup and type analysis.
//.
//. 'b' boolean
//. 'c' char
//. 'w' wchar_t
//. 'i' int (signed, unsigned)
//. 's' short (short int)
//. 'l' long (long int)
//. 'j' long long
//. 'f' float
//. 'd' double
//. 'r' long double
//. 'v' void
//.
//. 'T' template class (e.g. Foo<int,char> ==> T[3]Foo[2]ic.  [2] means
//.     the length of "ic".  It doesn't mean the number of template
//.     arguments.
//. 'e' ...
//. '?' no return type.  the return type of constructors
//. '*' non-type template parameter
//.
//. 'S' signed
//. 'U' unsigned
//. 'C' const
//. 'V' volatile
//.
//. 'P' pointer
//. 'R' reference
//. 'A' array (e.g. char[16] ==> A16_c)
//. 'F' function (e.g. char foo(int) ==> Fi_c)
//. 'M' pointer to member (e.g. Type::* ==> M[4]Type)
//.
//. 'Q' qualified class (e.g. X::YY ==> Q[2][1]X[2]YY, ::YY ==> Q[2][0][2]YY)
//.
//. [x] means (0x80 + x)
//. '0' means :: (global scope)
//.
//. Special function names:
//.
//. operator + ==> +
//. operator new[] ==> new[]
//. operator <type> ==> @<encoded type>		cast operator
class Encoding
{
public:
  struct char_traits
  {
    typedef unsigned char  char_type;
    typedef unsigned long  int_type;
    typedef std::streampos pos_type;
    typedef std::streamoff off_type;
    typedef std::mbstate_t state_type;

    static void assign(char_type &c1, const char_type &c2) { c1 = c2;}
    static bool eq(const char_type &c1, const char_type &c2) { return c1 == c2;}
    static bool lt(const char_type &c1, const char_type &c2) { return c1 < c2;}
    static int compare(const char_type *s1, const char_type *s2, std::size_t n) { return memcmp(s1, s2, n);}
    static std::size_t length(const char_type *s) { return strlen((const char *)s);}
    static const char_type *find(const char_type *s, std::size_t n, const char_type &a)
    { return static_cast<const char_type *>(memchr(s, a, n));}
    static char_type *move(char_type *s1, const char_type *s2, std::size_t n)
    { return static_cast<char_type *>(memmove(s1, s2, n));}
    static char_type *copy(char_type *s1, const char_type *s2, std::size_t n)
    { return static_cast<char_type *>(memcpy(s1, s2, n));}
    static char_type *assign(char_type *s, std::size_t n, char_type a)
    { return static_cast<char_type *>(memset(s, a, n));}
    static char_type to_char_type(const int_type &c) { return static_cast<char_type>(c);}
    static int_type to_int_type(const char_type &c) { return static_cast<int_type>(c);}
    static bool eq_int_type(const int_type &c1, const int_type &c2) { return c1 == c2;}
    static int_type eof() { return static_cast<int_type>(EOF);}
    static int_type not_eof(const int_type &c) { return !eq_int_type(c, eof()) ? c : to_int_type(char_type());}
  };

  typedef std::basic_string<unsigned char, char_traits> Code;
  typedef Code::const_iterator iterator;

  class name_iterator;

  static void do_init_static();

  Encoding() {}
  Encoding(const Code &b) : my_buffer(b) {}
  Encoding(const char *b) : my_buffer(b, b + strlen(b)) {}
  Encoding(const char *b, size_t s) : my_buffer(b, b + s) {}
  Encoding(iterator b, iterator e) : my_buffer(b, e) {}
  static Encoding simple_name(PTree::Atom const *name);

  void clear() { my_buffer.clear();}
  bool empty() const { return my_buffer.empty();}
  size_t size() const { return my_buffer.size();}
  iterator begin() const { return my_buffer.begin();}
  iterator end() const { return my_buffer.end();}
  unsigned char front() const { return *begin();}
  unsigned char at(size_t i) const { return my_buffer.at(i);}
  //. return a copy of the underlaying buffer
  //. FIXME: this is a temporary workaround while there are
  //. still places that use raw strings
  const char *copy() const;

  bool operator == (const Encoding &e) const { return my_buffer == e.my_buffer;}
  bool operator == (const std::string &s) const { return my_buffer == (const unsigned char *)s.c_str();}
  bool operator == (const char *s) const { return my_buffer == (const unsigned char *)s;}

  void prepend(unsigned char c) { my_buffer.insert(my_buffer.begin(), c);}
  void prepend(const char *p, size_t s) { my_buffer.insert(0, (const unsigned char *)p, s);}
  void prepend(const Encoding &e) { my_buffer.insert(0, e.my_buffer);}

  void append(unsigned char c) { my_buffer.append(1, c);}
  void append(const char *p, size_t s) { my_buffer.append((const unsigned char *)p, s);}
  void append(const Encoding &e) { my_buffer.append(e.my_buffer);}
  void append_with_length(const char *s, size_t n) { append(0x80 + n); append((const char *)s, n);}
  void append_with_length(const Encoding &e) { append(0x80 + e.size()); append(e);}

  unsigned char pop();
  void pop(size_t n) { my_buffer.erase(my_buffer.begin(), my_buffer.begin() + n);}

  void cv_qualify(const Node *, const Node * = 0);
  void simple_const() { append("Ci", 2);}
  void global_scope();
  void simple_name(const Node *);
  void anonymous();
  void template_(const Node *, const Encoding &);
  void qualified(int);
  void destructor(const Node *);
  void ptr_operator(int);
  void ptr_to_member(const Encoding &, int);
  void cast_operator(const Encoding &);
  void array() { prepend("A_", 2);}
  void array(unsigned long s);
  void function(const Encoding &e) { prepend(e);}
  void recursion(const Encoding &e) { prepend(e);}
  void start_func_args() { append('F');}
  void end_func_args() { append('_');}
  void void_() { append('v');}
  void ellipsis_arg() { append('e');}
  void no_return_type() { append('?');}
  void value_temp_param() { append('*');}

  name_iterator begin_name() const;
  name_iterator end_name() const;
//   name_iterator begin_function_parameters() const;
//   name_iterator end_function_parameters() const;
  Encoding function_return_type() const;

  //. if this Encoding represents a qualified name,
  //. return the name of the outer scope
  Encoding get_scope() const;
  //. if this Encoding represents a qualified name,
  //. return the name of the symbol inside the outer scope,
  //. else return the unmodified name
  Encoding get_symbol() const;
  Encoding get_template_name() const;
  Encoding get_template_arguments() const;

  std::string unmangled() const;

  PTree::Node *make_name();
  PTree::Node *make_qname();
  PTree::Node *make_ptree(PTree::Node *);
  bool is_simple_name() const { return front() >= 0x80;}
  bool is_global_scope() const { return front() == 0x80 && size() == 1;}
  bool is_qualified() const { return front() == 'Q';}
  bool is_function() const { return front() == 'F';}
  bool is_template_id() const { return front() == 'T';}
  PTree::Node *name_to_ptree();

  friend bool operator < (const Encoding &, const Encoding &);
  friend std::ostream &operator << (std::ostream &, const Encoding &);

private:

  //. Advance the iterator to the start of the next token.
  static iterator advance(iterator);
  iterator end_of_scope() const;
  static iterator end_name(iterator);

  Code my_buffer;

public:
  static PTree::Node *bool_t, *char_t, *wchar_t_t, *int_t, *short_t, *long_t,
		 *float_t, *double_t, *void_t;

  static PTree::Node *signed_t, *unsigned_t, *const_t, *volatile_t;

  static PTree::Node *operator_name, *new_operator, *anew_operator,
		 *delete_operator, *adelete_operator;

  static PTree::Node *star, *ampersand, *comma, *dots, *scope, *tilder,
		 *left_paren, *right_paren, *left_bracket, *right_bracket,
		 *left_angle, *right_angle;
};

class Encoding::name_iterator
{
public:
  name_iterator(iterator e, iterator i)
    : my_end(e),
      my_cursor(*i == 'Q' ? i + 2 : i),
      my_component(my_cursor, i == e ? my_cursor : Encoding::advance(my_cursor))
  {
  }
  name_iterator &operator++() { next(); return *this;}
  name_iterator operator++(int) { name_iterator retn(*this); next(); return retn;}
  Encoding const &operator*() const { return my_component;}
  Encoding const *operator->() const { return &my_component;}
  bool operator==(name_iterator const &i) const { return my_cursor == i.my_cursor;}
  bool operator!=(name_iterator const &i) const { return my_cursor != i.my_cursor;}

private:
  void next()
  {
    my_cursor += my_component.size();
    if (my_cursor != my_end)
      my_component = Encoding(my_cursor, Encoding::advance(my_cursor));
  }

  iterator const my_end;
  iterator       my_cursor;
  Encoding       my_component;
};

inline Encoding::name_iterator Encoding::begin_name() const
{
  return name_iterator(end(), begin());
}

inline Encoding::name_iterator Encoding::end_name() const
{
  return name_iterator(end(), end());
}

inline Encoding Encoding::function_return_type() const
{
  assert(is_function());
  // Find the token after the end-of-parameter-list marker ('_')
  iterator b = my_buffer.begin();
  while (*b != '_') ++b;
  iterator e = advance(++b);
  return Encoding(b, e);
}

inline bool operator < (const Encoding &e1, const Encoding &e2)
{
  return e1.my_buffer < e2.my_buffer;
}

inline std::ostream &operator << (std::ostream &os, const Encoding &e)
{
  for (Encoding::iterator i = e.begin();
       i != e.end();
       ++i)
    if(*i < 0x80) os.put(static_cast<char>(*i));
    else os << '[' << static_cast<int>(*i - 0x80) << ']';
  return os;
}

inline unsigned char Encoding::pop()
{
  unsigned char code = my_buffer[0];
  my_buffer.erase(0, 1);
  return code;
}

}
}

#endif
<|endoftext|>