<commit_before>// Copyright 2019 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/compiler/Translation/IREEVM.h"

#include "iree/compiler/Bindings/Native/Transforms/Passes.h"
#include "iree/compiler/Bindings/TFLite/Transforms/Passes.h"
#include "iree/compiler/ConstEval/Passes.h"
#include "iree/compiler/Dialect/Flow/Transforms/Passes.h"
#include "iree/compiler/Dialect/HAL/Transforms/Passes.h"
#include "iree/compiler/Dialect/Stream/Transforms/Passes.h"
#include "iree/compiler/Dialect/Util/Transforms/Passes.h"
#include "iree/compiler/Dialect/VM/Transforms/Passes.h"
#include "iree/compiler/InputConversion/Common/Passes.h"
#include "iree/compiler/InputConversion/MHLO/Passes.h"
#include "iree/compiler/InputConversion/TOSA/Passes.h"
#include "iree/compiler/Utils/PassUtils.h"
#include "iree/compiler/Utils/TracingUtils.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Translation.h"

#ifdef IREE_HAVE_EMITC_DIALECT
#include "iree/compiler/Dialect/VM/Target/C/CModuleTarget.h"
#include "iree/compiler/Dialect/VM/Target/C/TranslationFlags.h"
#endif  // IREE_HAVE_EMITC_DIALECT

namespace mlir {
namespace iree_compiler {

void BindingOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory bindingOptionsCategory(
      "IREE translation binding support options.");

  binder.opt<bool>(
      "iree-native-bindings-support", native,
      llvm::cl::desc(
          "Include runtime support for native IREE ABI-compatible bindings."),
      llvm::cl::cat(bindingOptionsCategory));
  binder.opt<bool>("iree-tflite-bindings-support", tflite,
                   llvm::cl::desc("Include runtime support for the IREE TFLite "
                                  "compatibility bindings."),
                   llvm::cl::cat(bindingOptionsCategory));
}

void InputDialectOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory inputDialectOptions(
      "IREE options for controlling the input transformations to apply.");

  binder.opt<InputDialectOptions::Type>(
      "iree-input-type", type,
      llvm::cl::desc("Specifies the input program representation."),
      llvm::cl::values(
          clEnumValN(InputDialectOptions::Type::none, "none",
                     "No input dialect transformation."),
          clEnumValN(InputDialectOptions::Type::tosa, "tosa",
                     "Legalize from TOSA ops."),
          clEnumValN(InputDialectOptions::Type::mhlo, "mhlo",
                     "Legalize from MHLO ops."),
          clEnumValN(
              InputDialectOptions::Type::xla, "xla",
              "Legalize from MHLO ops (with XLA cleanup preprocessing).")),
      llvm::cl::cat(inputDialectOptions));
}

void HighLevelOptimizationOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory category(
      "IREE options for controlling high level optimizations.");

  binder.opt<bool>(
      "iree-opt-const-eval", constEval,
      llvm::cl::desc("Enables eager evaluation of constants using the full "
                     "compiler and runtime."),
      llvm::cl::cat(category));
  binder.opt<bool>(
      "iree-opt-const-expr-hoisting", constExprHoisting,
      llvm::cl::desc(
          "Hoists the results of latent constant expressions into immutable "
          "global initializers for evaluation at program load."),
      llvm::cl::cat(category));
  binder.opt<bool>(
      "iree-opt-numeric-precision-reduction", numericPrecisionReduction,
      llvm::cl::desc(
          "Reduces numeric precision to lower bit depths where possible."),
      llvm::cl::cat(category));
  binder.opt<bool>("iree-opt-strip-assertions", stripAssertions,
                   llvm::cl::desc("Strips debug assertions after any useful "
                                  "information has been extracted."),
                   llvm::cl::cat(category));
}

void SchedulingOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory category(
      "IREE options for controlling host/device scheduling.");

  binder.opt<DumpOutputFormat>(
      "iree-scheduling-dump-statistics-format", dumpStatisticsFormat,
      llvm::cl::desc("Dumps statistics in the specified output format."),
      llvm::cl::cat(category),
      llvm::cl::values(
          clEnumValN(DumpOutputFormat::Pretty, "pretty",
                     "Human-readable pretty printed output."),
          clEnumValN(DumpOutputFormat::Verbose, "verbose",
                     "Pretty printed output with additional IR."),
          clEnumValN(DumpOutputFormat::CSV, "csv", "Comma separated values.")));
  binder.opt<std::string>("iree-scheduling-dump-statistics-file",
                          dumpStatisticsFile,
                          llvm::cl::desc("File path to write statistics to; or "
                                         "`` for stderr or `-` for stdout."),
                          llvm::cl::cat(category));
}

void buildIREEVMTransformPassPipeline(
    BindingOptions bindingOptions, InputDialectOptions inputOptions,
    HighLevelOptimizationOptions highLevelOptimizationOptions,
    SchedulingOptions schedulingOptions,
    IREE::HAL::TargetOptions executableOptions,
    IREE::VM::TargetOptions targetOptions, OpPassManager &passManager) {
  // Input pipelines can result in changes to the exported functions and types
  // and must run before generating bindings.
  // After input processing, there should only be IREE legal types in
  // signatures.
  switch (inputOptions.type) {
    case InputDialectOptions::Type::none:
      break;
    case InputDialectOptions::Type::tosa:
      buildTOSAInputConversionPassPipeline(passManager);
      break;
    case InputDialectOptions::Type::mhlo:
      MHLO::buildMHLOInputConversionPassPipeline(passManager);
      break;
    case InputDialectOptions::Type::xla:
      MHLO::buildXLACleanupPassPipeline(passManager);
      MHLO::buildMHLOInputConversionPassPipeline(passManager);
      break;
  }
  buildCommonInputConversionPassPipeline(passManager);

  // Now that inputs are legalized, generate wrapper for entry functions.
  if (bindingOptions.native) {
    IREE::ABI::buildTransformPassPipeline(passManager);
  }
  if (bindingOptions.tflite) {
    IREE::TFLite::buildTransformPassPipeline(passManager);
  }

  IREE::Flow::TransformOptions flowOptions;
  flowOptions.constExprHoisting =
      highLevelOptimizationOptions.constExprHoisting;
  if (highLevelOptimizationOptions.constEval) {
    flowOptions.buildConstEvalPassPipeline = [](OpPassManager &passManager) {
      passManager.addPass(ConstEval::createJitGlobalsPass());
    };
  }
  flowOptions.numericPrecisionReduction =
      highLevelOptimizationOptions.numericPrecisionReduction;

  if (highLevelOptimizationOptions.stripAssertions) {
    // Strip std.assert & co after we perform optimizations; prior to this we
    // may use the assertions to derive information during analysis.
    passManager.addPass(IREE::Util::createStripDebugOpsPass());
  }

  IREE::Stream::TransformOptions streamOptions;
  // TODO(benvanik): find a way to share the enums w/o circular deps.
  streamOptions.dumpStatisticsFormat =
      (IREE::Stream::DumpOutputFormat)schedulingOptions.dumpStatisticsFormat;
  streamOptions.dumpStatisticsFile = schedulingOptions.dumpStatisticsFile;

  IREE::Flow::buildFlowTransformPassPipeline(passManager, flowOptions);
  IREE::Stream::buildStreamTransformPassPipeline(passManager, streamOptions);
  IREE::HAL::buildHALTransformPassPipeline(passManager, executableOptions);
  IREE::VM::buildVMTransformPassPipeline(passManager, targetOptions);
  passManager.addPass(IREE::Util::createDropCompilerHintsPass());
}

void buildDefaultIREEVMTransformPassPipeline(OpPassManager &passManager) {
  buildIREEVMTransformPassPipeline(
      BindingOptions::FromFlags::get(), InputDialectOptions::FromFlags::get(),
      HighLevelOptimizationOptions::FromFlags::get(),
      SchedulingOptions::FromFlags::get(),
      IREE::HAL::TargetOptions::FromFlags::get(),
      IREE::VM::TargetOptions::FromFlags::get(), passManager);
}

void registerIREEVMTransformPassPipeline() {
  PassPipelineRegistration<> transformPassPipeline(
      "iree-transformation-pipeline",
      "Runs the full IREE input to VM transformation pipeline",
      [](OpPassManager &passManager) {
        buildDefaultIREEVMTransformPassPipeline(passManager);
      });
}

// Converts from our source to a vm.module in canonical form.
// After this completes we have a non-bytecode-specific vm.module that we
// could lower to other forms (LLVM IR, C, etc).
static LogicalResult translateFromMLIRToVM(
    ModuleOp moduleOp, BindingOptions bindingOptions,
    InputDialectOptions inputOptions,
    HighLevelOptimizationOptions highLevelOptimizationOptions,
    SchedulingOptions schedulingOptions,
    IREE::HAL::TargetOptions executableOptions,
    IREE::VM::TargetOptions targetOptions) {
  PassManager passManager(moduleOp.getContext());
  mlir::applyPassManagerCLOptions(passManager);
  mlir::applyDefaultTimingPassManagerCLOptions(passManager);
  passManager.addInstrumentation(std::make_unique<PassTracing>());
  buildIREEVMTransformPassPipeline(
      bindingOptions, inputOptions, highLevelOptimizationOptions,
      schedulingOptions, executableOptions, targetOptions, passManager);
  if (failed(passManager.run(moduleOp))) {
    return moduleOp.emitError() << "conversion from source -> vm failed";
  }
  return success();
}

// Translates an MLIR module containing a set of supported IREE input dialects
// to an IREE VM bytecode module for loading at runtime.
//
// See iree/schemas/bytecode_module_def.fbs for the description of the
// serialized module format.
//
// Exposed via the --iree-mlir-to-vm-bytecode-module translation.
static LogicalResult translateFromMLIRToVMBytecodeModuleWithFlags(
    ModuleOp moduleOp, llvm::raw_ostream &output) {
  mlir::registerPassManagerCLOptions();
  auto bindingOptions = BindingOptions::FromFlags::get();
  auto inputOptions = InputDialectOptions::FromFlags::get();
  auto highLevelOptimizationOptions =
      HighLevelOptimizationOptions::FromFlags::get();
  auto schedulingOptions = SchedulingOptions::FromFlags::get();
  auto halTargetOptions = IREE::HAL::TargetOptions::FromFlags::get();
  auto vmTargetOptions = IREE::VM::TargetOptions::FromFlags::get();
  auto bytecodeTargetOptions =
      IREE::VM::BytecodeTargetOptions::FromFlags::get();
  auto result = translateFromMLIRToVM(
      moduleOp, bindingOptions, inputOptions, highLevelOptimizationOptions,
      schedulingOptions, halTargetOptions, vmTargetOptions);
  if (failed(result)) {
    return result;
  }
  return translateModuleToBytecode(moduleOp, bytecodeTargetOptions, output);
}

#ifdef IREE_HAVE_EMITC_DIALECT
// Translates an MLIR module containing a set of supported IREE input dialects
// to an IREE VM C module.
//
// Exposed via the --iree-mlir-to-vm-c-module translation.
static LogicalResult translateFromMLIRToVMCModuleWithFlags(
    ModuleOp moduleOp, llvm::raw_ostream &output) {
  mlir::registerPassManagerCLOptions();
  auto bindingOptions = BindingOptions::FromFlags::get();
  auto inputOptions = InputDialectOptions::FromFlags::get();
  auto highLevelOptimizationOptions =
      HighLevelOptimizationOptions::FromFlags::get();
  auto schedulingOptions = SchedulingOptions::FromFlags::get();
  auto halTargetOptions = IREE::HAL::TargetOptions::FromFlags::get();
  auto vmTargetOptions = IREE::VM::TargetOptions::FromFlags::get();
  auto cTargetOptions = IREE::VM::getCTargetOptionsFromFlags();
  auto result = translateFromMLIRToVM(
      moduleOp, bindingOptions, inputOptions, highLevelOptimizationOptions,
      schedulingOptions, halTargetOptions, vmTargetOptions);
  if (failed(result)) {
    return result;
  }
  // Serialize to c code.
  return mlir::iree_compiler::IREE::VM::translateModuleToC(
      moduleOp, cTargetOptions, output);
}
#endif  // IREE_HAVE_EMITC_DIALECT

void registerIREEVMTranslationFlags() {
  BindingOptions::FromFlags::get();
  InputDialectOptions::FromFlags::get();
  HighLevelOptimizationOptions::FromFlags::get();
  IREE::HAL::TargetOptions::FromFlags::get();
  IREE::VM::TargetOptions::FromFlags::get();
  IREE::VM::BytecodeTargetOptions::FromFlags::get();
}

void registerIREEVMTranslation() {
  registerIREEVMTranslationFlags();
  TranslateFromMLIRRegistration toVMBytecodeModuleWithFlags(
      "iree-mlir-to-vm-bytecode-module",
      translateFromMLIRToVMBytecodeModuleWithFlags);

#ifdef IREE_HAVE_EMITC_DIALECT
  TranslateFromMLIRRegistration toVMCModuleWithFlags(
      "iree-mlir-to-vm-c-module", translateFromMLIRToVMCModuleWithFlags);
#endif  // IREE_HAVE_EMITC_DIALECT
}

}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>Register `-iree-scheduling-dump-statistics-*` flags. (#8182)<commit_after>// Copyright 2019 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/compiler/Translation/IREEVM.h"

#include "iree/compiler/Bindings/Native/Transforms/Passes.h"
#include "iree/compiler/Bindings/TFLite/Transforms/Passes.h"
#include "iree/compiler/ConstEval/Passes.h"
#include "iree/compiler/Dialect/Flow/Transforms/Passes.h"
#include "iree/compiler/Dialect/HAL/Transforms/Passes.h"
#include "iree/compiler/Dialect/Stream/Transforms/Passes.h"
#include "iree/compiler/Dialect/Util/Transforms/Passes.h"
#include "iree/compiler/Dialect/VM/Transforms/Passes.h"
#include "iree/compiler/InputConversion/Common/Passes.h"
#include "iree/compiler/InputConversion/MHLO/Passes.h"
#include "iree/compiler/InputConversion/TOSA/Passes.h"
#include "iree/compiler/Utils/PassUtils.h"
#include "iree/compiler/Utils/TracingUtils.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Translation.h"

#ifdef IREE_HAVE_EMITC_DIALECT
#include "iree/compiler/Dialect/VM/Target/C/CModuleTarget.h"
#include "iree/compiler/Dialect/VM/Target/C/TranslationFlags.h"
#endif  // IREE_HAVE_EMITC_DIALECT

namespace mlir {
namespace iree_compiler {

void BindingOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory bindingOptionsCategory(
      "IREE translation binding support options.");

  binder.opt<bool>(
      "iree-native-bindings-support", native,
      llvm::cl::desc(
          "Include runtime support for native IREE ABI-compatible bindings."),
      llvm::cl::cat(bindingOptionsCategory));
  binder.opt<bool>("iree-tflite-bindings-support", tflite,
                   llvm::cl::desc("Include runtime support for the IREE TFLite "
                                  "compatibility bindings."),
                   llvm::cl::cat(bindingOptionsCategory));
}

void InputDialectOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory inputDialectOptions(
      "IREE options for controlling the input transformations to apply.");

  binder.opt<InputDialectOptions::Type>(
      "iree-input-type", type,
      llvm::cl::desc("Specifies the input program representation."),
      llvm::cl::values(
          clEnumValN(InputDialectOptions::Type::none, "none",
                     "No input dialect transformation."),
          clEnumValN(InputDialectOptions::Type::tosa, "tosa",
                     "Legalize from TOSA ops."),
          clEnumValN(InputDialectOptions::Type::mhlo, "mhlo",
                     "Legalize from MHLO ops."),
          clEnumValN(
              InputDialectOptions::Type::xla, "xla",
              "Legalize from MHLO ops (with XLA cleanup preprocessing).")),
      llvm::cl::cat(inputDialectOptions));
}

void HighLevelOptimizationOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory category(
      "IREE options for controlling high level optimizations.");

  binder.opt<bool>(
      "iree-opt-const-eval", constEval,
      llvm::cl::desc("Enables eager evaluation of constants using the full "
                     "compiler and runtime."),
      llvm::cl::cat(category));
  binder.opt<bool>(
      "iree-opt-const-expr-hoisting", constExprHoisting,
      llvm::cl::desc(
          "Hoists the results of latent constant expressions into immutable "
          "global initializers for evaluation at program load."),
      llvm::cl::cat(category));
  binder.opt<bool>(
      "iree-opt-numeric-precision-reduction", numericPrecisionReduction,
      llvm::cl::desc(
          "Reduces numeric precision to lower bit depths where possible."),
      llvm::cl::cat(category));
  binder.opt<bool>("iree-opt-strip-assertions", stripAssertions,
                   llvm::cl::desc("Strips debug assertions after any useful "
                                  "information has been extracted."),
                   llvm::cl::cat(category));
}

void SchedulingOptions::bindOptions(OptionsBinder &binder) {
  static llvm::cl::OptionCategory category(
      "IREE options for controlling host/device scheduling.");

  binder.opt<DumpOutputFormat>(
      "iree-scheduling-dump-statistics-format", dumpStatisticsFormat,
      llvm::cl::desc("Dumps statistics in the specified output format."),
      llvm::cl::cat(category),
      llvm::cl::values(
          clEnumValN(DumpOutputFormat::Pretty, "pretty",
                     "Human-readable pretty printed output."),
          clEnumValN(DumpOutputFormat::Verbose, "verbose",
                     "Pretty printed output with additional IR."),
          clEnumValN(DumpOutputFormat::CSV, "csv", "Comma separated values.")));
  binder.opt<std::string>("iree-scheduling-dump-statistics-file",
                          dumpStatisticsFile,
                          llvm::cl::desc("File path to write statistics to; or "
                                         "`` for stderr or `-` for stdout."),
                          llvm::cl::cat(category));
}

void buildIREEVMTransformPassPipeline(
    BindingOptions bindingOptions, InputDialectOptions inputOptions,
    HighLevelOptimizationOptions highLevelOptimizationOptions,
    SchedulingOptions schedulingOptions,
    IREE::HAL::TargetOptions executableOptions,
    IREE::VM::TargetOptions targetOptions, OpPassManager &passManager) {
  // Input pipelines can result in changes to the exported functions and types
  // and must run before generating bindings.
  // After input processing, there should only be IREE legal types in
  // signatures.
  switch (inputOptions.type) {
    case InputDialectOptions::Type::none:
      break;
    case InputDialectOptions::Type::tosa:
      buildTOSAInputConversionPassPipeline(passManager);
      break;
    case InputDialectOptions::Type::mhlo:
      MHLO::buildMHLOInputConversionPassPipeline(passManager);
      break;
    case InputDialectOptions::Type::xla:
      MHLO::buildXLACleanupPassPipeline(passManager);
      MHLO::buildMHLOInputConversionPassPipeline(passManager);
      break;
  }
  buildCommonInputConversionPassPipeline(passManager);

  // Now that inputs are legalized, generate wrapper for entry functions.
  if (bindingOptions.native) {
    IREE::ABI::buildTransformPassPipeline(passManager);
  }
  if (bindingOptions.tflite) {
    IREE::TFLite::buildTransformPassPipeline(passManager);
  }

  IREE::Flow::TransformOptions flowOptions;
  flowOptions.constExprHoisting =
      highLevelOptimizationOptions.constExprHoisting;
  if (highLevelOptimizationOptions.constEval) {
    flowOptions.buildConstEvalPassPipeline = [](OpPassManager &passManager) {
      passManager.addPass(ConstEval::createJitGlobalsPass());
    };
  }
  flowOptions.numericPrecisionReduction =
      highLevelOptimizationOptions.numericPrecisionReduction;

  if (highLevelOptimizationOptions.stripAssertions) {
    // Strip std.assert & co after we perform optimizations; prior to this we
    // may use the assertions to derive information during analysis.
    passManager.addPass(IREE::Util::createStripDebugOpsPass());
  }

  IREE::Stream::TransformOptions streamOptions;
  // TODO(benvanik): find a way to share the enums w/o circular deps.
  streamOptions.dumpStatisticsFormat =
      (IREE::Stream::DumpOutputFormat)schedulingOptions.dumpStatisticsFormat;
  streamOptions.dumpStatisticsFile = schedulingOptions.dumpStatisticsFile;

  IREE::Flow::buildFlowTransformPassPipeline(passManager, flowOptions);
  IREE::Stream::buildStreamTransformPassPipeline(passManager, streamOptions);
  IREE::HAL::buildHALTransformPassPipeline(passManager, executableOptions);
  IREE::VM::buildVMTransformPassPipeline(passManager, targetOptions);
  passManager.addPass(IREE::Util::createDropCompilerHintsPass());
}

void buildDefaultIREEVMTransformPassPipeline(OpPassManager &passManager) {
  buildIREEVMTransformPassPipeline(
      BindingOptions::FromFlags::get(), InputDialectOptions::FromFlags::get(),
      HighLevelOptimizationOptions::FromFlags::get(),
      SchedulingOptions::FromFlags::get(),
      IREE::HAL::TargetOptions::FromFlags::get(),
      IREE::VM::TargetOptions::FromFlags::get(), passManager);
}

void registerIREEVMTransformPassPipeline() {
  PassPipelineRegistration<> transformPassPipeline(
      "iree-transformation-pipeline",
      "Runs the full IREE input to VM transformation pipeline",
      [](OpPassManager &passManager) {
        buildDefaultIREEVMTransformPassPipeline(passManager);
      });
}

// Converts from our source to a vm.module in canonical form.
// After this completes we have a non-bytecode-specific vm.module that we
// could lower to other forms (LLVM IR, C, etc).
static LogicalResult translateFromMLIRToVM(
    ModuleOp moduleOp, BindingOptions bindingOptions,
    InputDialectOptions inputOptions,
    HighLevelOptimizationOptions highLevelOptimizationOptions,
    SchedulingOptions schedulingOptions,
    IREE::HAL::TargetOptions executableOptions,
    IREE::VM::TargetOptions targetOptions) {
  PassManager passManager(moduleOp.getContext());
  mlir::applyPassManagerCLOptions(passManager);
  mlir::applyDefaultTimingPassManagerCLOptions(passManager);
  passManager.addInstrumentation(std::make_unique<PassTracing>());
  buildIREEVMTransformPassPipeline(
      bindingOptions, inputOptions, highLevelOptimizationOptions,
      schedulingOptions, executableOptions, targetOptions, passManager);
  if (failed(passManager.run(moduleOp))) {
    return moduleOp.emitError() << "conversion from source -> vm failed";
  }
  return success();
}

// Translates an MLIR module containing a set of supported IREE input dialects
// to an IREE VM bytecode module for loading at runtime.
//
// See iree/schemas/bytecode_module_def.fbs for the description of the
// serialized module format.
//
// Exposed via the --iree-mlir-to-vm-bytecode-module translation.
static LogicalResult translateFromMLIRToVMBytecodeModuleWithFlags(
    ModuleOp moduleOp, llvm::raw_ostream &output) {
  mlir::registerPassManagerCLOptions();
  auto bindingOptions = BindingOptions::FromFlags::get();
  auto inputOptions = InputDialectOptions::FromFlags::get();
  auto highLevelOptimizationOptions =
      HighLevelOptimizationOptions::FromFlags::get();
  auto schedulingOptions = SchedulingOptions::FromFlags::get();
  auto halTargetOptions = IREE::HAL::TargetOptions::FromFlags::get();
  auto vmTargetOptions = IREE::VM::TargetOptions::FromFlags::get();
  auto bytecodeTargetOptions =
      IREE::VM::BytecodeTargetOptions::FromFlags::get();
  auto result = translateFromMLIRToVM(
      moduleOp, bindingOptions, inputOptions, highLevelOptimizationOptions,
      schedulingOptions, halTargetOptions, vmTargetOptions);
  if (failed(result)) {
    return result;
  }
  return translateModuleToBytecode(moduleOp, bytecodeTargetOptions, output);
}

#ifdef IREE_HAVE_EMITC_DIALECT
// Translates an MLIR module containing a set of supported IREE input dialects
// to an IREE VM C module.
//
// Exposed via the --iree-mlir-to-vm-c-module translation.
static LogicalResult translateFromMLIRToVMCModuleWithFlags(
    ModuleOp moduleOp, llvm::raw_ostream &output) {
  mlir::registerPassManagerCLOptions();
  auto bindingOptions = BindingOptions::FromFlags::get();
  auto inputOptions = InputDialectOptions::FromFlags::get();
  auto highLevelOptimizationOptions =
      HighLevelOptimizationOptions::FromFlags::get();
  auto schedulingOptions = SchedulingOptions::FromFlags::get();
  auto halTargetOptions = IREE::HAL::TargetOptions::FromFlags::get();
  auto vmTargetOptions = IREE::VM::TargetOptions::FromFlags::get();
  auto cTargetOptions = IREE::VM::getCTargetOptionsFromFlags();
  auto result = translateFromMLIRToVM(
      moduleOp, bindingOptions, inputOptions, highLevelOptimizationOptions,
      schedulingOptions, halTargetOptions, vmTargetOptions);
  if (failed(result)) {
    return result;
  }
  // Serialize to c code.
  return mlir::iree_compiler::IREE::VM::translateModuleToC(
      moduleOp, cTargetOptions, output);
}
#endif  // IREE_HAVE_EMITC_DIALECT

void registerIREEVMTranslationFlags() {
  BindingOptions::FromFlags::get();
  InputDialectOptions::FromFlags::get();
  HighLevelOptimizationOptions::FromFlags::get();
  IREE::HAL::TargetOptions::FromFlags::get();
  IREE::VM::TargetOptions::FromFlags::get();
  IREE::VM::BytecodeTargetOptions::FromFlags::get();
  SchedulingOptions::FromFlags::get();
}

void registerIREEVMTranslation() {
  registerIREEVMTranslationFlags();
  TranslateFromMLIRRegistration toVMBytecodeModuleWithFlags(
      "iree-mlir-to-vm-bytecode-module",
      translateFromMLIRToVMBytecodeModuleWithFlags);

#ifdef IREE_HAVE_EMITC_DIALECT
  TranslateFromMLIRRegistration toVMCModuleWithFlags(
      "iree-mlir-to-vm-c-module", translateFromMLIRToVMCModuleWithFlags);
#endif  // IREE_HAVE_EMITC_DIALECT
}

}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>


<commit_before>
#include "tablemodelanovamodel.h"

#include <QMimeData>
#include <QDebug>

#include "qutils.h"
#include <boost/foreach.hpp>

#include "options/optionboolean.h"

using namespace std;

TableModelAnovaModel::TableModelAnovaModel(QObject *parent)
	: TableModel(parent)
{
	_boundTo = NULL;

	_terms.setSortParent(_variables);
}

QVariant TableModelAnovaModel::data(const QModelIndex &index, int role) const
{
	if (_boundTo == NULL || index.isValid() == false)
		return QVariant();

	if (role == Qt::DisplayRole)
	{
		int colNo = index.column();
		int rowNo = index.row();
		Options *row = _rows.at(rowNo);

		if (colNo == 0) {

			OptionTerms *termOption = static_cast<OptionTerms *>(row->get(0));
			Term t(termOption->value().front());
			return t.asQString();
		}
	}
	else if (role == Qt::CheckStateRole)
	{
		int colNo = index.column();
		int rowNo = index.row();
		Options *row = _rows.at(rowNo);

		if (colNo == 1)
		{
			OptionBoolean *booleanOption = static_cast<OptionBoolean *>(row->get(1));
			return booleanOption->value() ? Qt::Checked : Qt::Unchecked;
		}
	}

	return QVariant();
}

int TableModelAnovaModel::rowCount(const QModelIndex &) const
{
	if (_boundTo == NULL)
		return 0;

	return _rows.size();
}

int TableModelAnovaModel::columnCount(const QModelIndex &) const
{
	if (_boundTo == NULL)
		return 0;

	return _boundTo->rowTemplate()->size();
}

bool TableModelAnovaModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
	if (index.isValid() == false)
		return false;

	if (index.column() == 1 && role == Qt::CheckStateRole)
	{
		bool checked = value.toInt() == Qt::Checked;

		Options *row = _rows.at(index.row());
		OptionBoolean *booleanOption = static_cast<OptionBoolean *>(row->get(1));
		booleanOption->setValue(checked);
		updateNuisances(checked);

		_boundTo->setValue(_rows);

		return true;
	}

	return false;
}

QStringList TableModelAnovaModel::mimeTypes() const
{
	QStringList types;

	types << "application/vnd.list.term";

	return types;
}

void TableModelAnovaModel::setVariables(const Terms &fixedFactors, const Terms &randomFactors, const Terms &covariates)
{
	_fixedFactors = fixedFactors;
	_randomFactors = randomFactors;
	_covariates = covariates;

	Terms all;
	all.add(fixedFactors);
	all.add(randomFactors);
	all.add(covariates);

	_variables.set(all);

	emit variablesAvailableChanged();
}

const Terms &TableModelAnovaModel::variables() const
{
	return _variables;
}

void TableModelAnovaModel::bindTo(Option *option)
{
	_boundTo = dynamic_cast<OptionsTable *>(option);

	beginResetModel();

	_rows = _boundTo->value();

	foreach (Options *row, _rows)
	{
		OptionTerm *nameOption = static_cast<OptionTerm*>(row->get(0));
		vector<string> term = nameOption->term();

		_terms.add(Term(term));
	}

	endResetModel();
}

void TableModelAnovaModel::mimeDataMoved(const QModelIndexList &indexes)
{
	// sort indices, and delete from end to beginning

	QModelIndexList sorted = indexes;
	qSort(sorted.begin(), sorted.end(), qGreater<QModelIndex>());

	int lastRowDeleted = -1;

	Terms terms = _terms;

	foreach (const QModelIndex &index, sorted)
	{
		int rowNo = index.row();
		if (rowNo != lastRowDeleted)
			terms.remove(index.row());
		lastRowDeleted = rowNo;
	}

	setTerms(terms);
}

const Terms &TableModelAnovaModel::terms() const
{
	return _terms;
}

void TableModelAnovaModel::addFixedFactors(const Terms &terms)
{
	_fixedFactors.add(terms);
	_variables.add(terms);

	Terms existingTerms = _terms;

	Terms newTerms = _terms;
	newTerms.discardWhatDoesContainTheseComponents(_randomFactors);
	newTerms.discardWhatDoesContainTheseComponents(_covariates);
	existingTerms.add(newTerms.ffCombinations(terms));

	setTerms(existingTerms);

	emit variablesAvailableChanged();
}

void TableModelAnovaModel::addRandomFactors(const Terms &terms)
{
	_randomFactors.add(terms);
	_variables.add(terms);

	Terms newTerms = _terms;
	newTerms.add(terms);

	setTerms(newTerms, true);

	emit variablesAvailableChanged();
}

void TableModelAnovaModel::addCovariates(const Terms &terms)
{
	_covariates.add(terms);
	_variables.add(terms);

	Terms newTerms = _terms;
	newTerms.add(terms);

	setTerms(newTerms);

	emit variablesAvailableChanged();
}

void TableModelAnovaModel::removeVariables(const Terms &terms)
{
	_variables.remove(terms);
	_fixedFactors.remove(terms);
	_randomFactors.remove(terms);
	_covariates.remove(terms);

	Terms newTerms = _terms;
	newTerms.discardWhatDoesContainTheseComponents(terms);

	setTerms(newTerms);

	emit variablesAvailableChanged();
}

bool TableModelAnovaModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
	Q_UNUSED(action);
	Q_UNUSED(row);
	Q_UNUSED(column);
	Q_UNUSED(parent);

	if (mimeTypes().contains("application/vnd.list.term"))
	{
		QByteArray encodedData = data->data("application/vnd.list.term");
		QDataStream stream(&encodedData, QIODevice::ReadOnly);

		if (stream.atEnd())
			return false;

		return true;
	}

	return false;
}

bool TableModelAnovaModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent, int assignType)
{
	if (action == Qt::IgnoreAction)
		return true;

	if ( ! canDropMimeData(data, action, row, column, parent))
		return false;

	if ( ! data->hasFormat("application/vnd.list.term"))
		return false;

	QByteArray encodedData = data->data("application/vnd.list.term");

	Terms dropped;
	dropped.setSortParent(_variables);
	dropped.set(encodedData);

	Terms newTerms;

	switch (assignType)
	{
	case Cross:
		newTerms = dropped.crossCombinations();
		break;
	case Interaction:
		newTerms = dropped.wayCombinations(dropped.size());
		break;
	case MainEffects:
		newTerms = dropped.wayCombinations(1);
		break;
	case All2Way:
		newTerms = dropped.wayCombinations(2);
		break;
	case All3Way:
		newTerms = dropped.wayCombinations(3);
		break;
	case All4Way:
		newTerms = dropped.wayCombinations(4);
		break;
	case All5Way:
		newTerms = dropped.wayCombinations(5);
		break;
	default:
		(void)newTerms;
	}

	assign(newTerms);

	return true;
}

bool TableModelAnovaModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
	return dropMimeData(data, action, row, column, parent, Cross);
}

QMimeData *TableModelAnovaModel::mimeData(const QModelIndexList &indexes) const
{
	/* returns dummy data. when the user drags entries away from this listbox
	 * it means that they're deleting entries, so there's no point populating
	 * this data object properly
	 */

	Q_UNUSED(indexes);

	QMimeData *mimeData = new QMimeData();
	QByteArray encodedData;

	QDataStream dataStream(&encodedData, QIODevice::WriteOnly);

	dataStream << 0;

	mimeData->setData("application/vnd.list.term", encodedData);

	return mimeData;
}

Qt::ItemFlags TableModelAnovaModel::flags(const QModelIndex &index) const
{
	if (index.isValid())
	{
		if (index.column() == 0)
			return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
		else
			return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
	}
	else
	{
		return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
	}
}

QVariant TableModelAnovaModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (orientation == Qt::Horizontal)
	{
		if (role == Qt::DisplayRole)
		{
			if (section == 0)
				return "Model Terms";
			else if (section == 1)
				return "Is Nuisance";
		}
		else
		{
			if (section == 1 && role == Qt::SizeHintRole)
				return QSize(50, -1);
		}
	}

	return QVariant();
}

Qt::DropActions TableModelAnovaModel::supportedDropActions() const
{
	return Qt::CopyAction;
}

Qt::DropActions TableModelAnovaModel::supportedDragActions() const
{
	return Qt::MoveAction;
}

OptionTerm *TableModelAnovaModel::termOptionFromRow(Options *row)
{
	return static_cast<OptionTerm *>(row->get(0));
}

void TableModelAnovaModel::setTerms(const Terms &terms, bool newTermsAreNuisance)
{
	_terms.set(terms);

	if (_boundTo == NULL)
		return;

	beginResetModel();

	Terms::const_iterator itr;
	vector<Options *>::iterator otr;

	otr = _rows.begin();

	while (otr != _rows.end())
	{
		Options *row = *otr;
		OptionTerm *termCell = termOptionFromRow(row);
		Term existingTerm = Term(termCell->term());

		bool shouldRemove = true;

		itr = terms.begin();

		while (itr != terms.end())
		{
			const Term &term = *itr;

			if (term == existingTerm)
			{
				shouldRemove = false;
				break;
			}

			itr++;
		}

		if (shouldRemove)
		{
			_rows.erase(otr);
			delete row;
		}
		else
		{
			otr++;
		}
	}

	itr = terms.begin();

	for (int i = 0; i < terms.size(); i++)
	{
		const Term &term = *itr;

		if (i < _rows.size())
		{
			otr = _rows.begin();
			otr += i;
			Options *row = *otr;
			OptionTerm *termCell = termOptionFromRow(row);
			Term existingTerm = Term(termCell->term());

			if (existingTerm != term)
			{
				Options *row = static_cast<Options *>(_boundTo->rowTemplate()->clone());
				OptionTerms *termCell = static_cast<OptionTerms *>(row->get(0));
				termCell->setValue(term.scomponents());

				if (row->size() > 1 && newTermsAreNuisance)
				{
					OptionBoolean *nuisance = static_cast<OptionBoolean *>(row->get(1));
					nuisance->setValue(true);
				}

				_rows.insert(otr, row);
			}
		}
		else
		{
			Options *row = static_cast<Options *>(_boundTo->rowTemplate()->clone());
			OptionTerms *termCell = static_cast<OptionTerms *>(row->get(0));
			termCell->setValue(term.scomponents());

			if (row->size() > 1 && newTermsAreNuisance)
			{
				OptionBoolean *nuisance = static_cast<OptionBoolean *>(row->get(1));
				nuisance->setValue(true);
			}

			_rows.push_back(row);
		}

		itr++;
	}

	updateNuisances();

	_boundTo->setValue(_rows);

	endResetModel();

	emit termsChanged();
}

void TableModelAnovaModel::clear()
{
	setTerms(Terms());
}

void TableModelAnovaModel::assign(const Terms &terms)
{
	Terms t = _terms;
	t.add(terms);
	setTerms(t);
}

void TableModelAnovaModel::updateNuisances(bool checked)
{
	// if a higher order interaction is specified as nuisance, then all lower order terms should be changed to nuisance as well

	for (int i = 0; i < _rows.size(); i++)
	{
		Options *row = _rows.at(i);
		OptionTerm *termOption = static_cast<OptionTerm*>(row->get(0));
		OptionBoolean *nuisanceOption = static_cast<OptionBoolean*>(row->get(1));
		Term term = Term(termOption->term());

		if (nuisanceOption->value() == checked)
		{
			for (int j = 0; j < _rows.size(); j++)
			{
				if (i == j)
					continue;

				Options *r = _rows.at(j);

				OptionTerm *tOption = static_cast<OptionTerm*>(r->get(0));
				OptionBoolean *nOption = static_cast<OptionBoolean*>(r->get(1));
				Term t = Term(tOption->term());

				if (checked)
				{
					if (t.containsAny(term))
						nOption->setValue(true);
				}
				else
				{
					if (t.containsAll(term))
						nOption->setValue(false);
				}
			}
		}
	}

	emit dataChanged(this->index(0,1), this->index(_rows.size() - 1, 1));
}
<commit_msg>B ANOVAs: Fix to nuisance checkbox behaviour<commit_after>
#include "tablemodelanovamodel.h"

#include <QMimeData>
#include <QDebug>

#include "qutils.h"
#include <boost/foreach.hpp>

#include "options/optionboolean.h"

using namespace std;

TableModelAnovaModel::TableModelAnovaModel(QObject *parent)
	: TableModel(parent)
{
	_boundTo = NULL;

	_terms.setSortParent(_variables);
}

QVariant TableModelAnovaModel::data(const QModelIndex &index, int role) const
{
	if (_boundTo == NULL || index.isValid() == false)
		return QVariant();

	if (role == Qt::DisplayRole)
	{
		int colNo = index.column();
		int rowNo = index.row();
		Options *row = _rows.at(rowNo);

		if (colNo == 0) {

			OptionTerms *termOption = static_cast<OptionTerms *>(row->get(0));
			Term t(termOption->value().front());
			return t.asQString();
		}
	}
	else if (role == Qt::CheckStateRole)
	{
		int colNo = index.column();
		int rowNo = index.row();
		Options *row = _rows.at(rowNo);

		if (colNo == 1)
		{
			OptionBoolean *booleanOption = static_cast<OptionBoolean *>(row->get(1));
			return booleanOption->value() ? Qt::Checked : Qt::Unchecked;
		}
	}

	return QVariant();
}

int TableModelAnovaModel::rowCount(const QModelIndex &) const
{
	if (_boundTo == NULL)
		return 0;

	return _rows.size();
}

int TableModelAnovaModel::columnCount(const QModelIndex &) const
{
	if (_boundTo == NULL)
		return 0;

	return _boundTo->rowTemplate()->size();
}

bool TableModelAnovaModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
	if (index.isValid() == false)
		return false;

	if (index.column() == 1 && role == Qt::CheckStateRole)
	{
		bool checked = value.toInt() == Qt::Checked;

		Options *row = _rows.at(index.row());
		OptionBoolean *booleanOption = static_cast<OptionBoolean *>(row->get(1));
		booleanOption->setValue(checked);
		updateNuisances(checked);

		_boundTo->setValue(_rows);

		return true;
	}

	return false;
}

QStringList TableModelAnovaModel::mimeTypes() const
{
	QStringList types;

	types << "application/vnd.list.term";

	return types;
}

void TableModelAnovaModel::setVariables(const Terms &fixedFactors, const Terms &randomFactors, const Terms &covariates)
{
	_fixedFactors = fixedFactors;
	_randomFactors = randomFactors;
	_covariates = covariates;

	Terms all;
	all.add(fixedFactors);
	all.add(randomFactors);
	all.add(covariates);

	_variables.set(all);

	emit variablesAvailableChanged();
}

const Terms &TableModelAnovaModel::variables() const
{
	return _variables;
}

void TableModelAnovaModel::bindTo(Option *option)
{
	_boundTo = dynamic_cast<OptionsTable *>(option);

	beginResetModel();

	_rows = _boundTo->value();

	foreach (Options *row, _rows)
	{
		OptionTerm *nameOption = static_cast<OptionTerm*>(row->get(0));
		vector<string> term = nameOption->term();

		_terms.add(Term(term));
	}

	endResetModel();
}

void TableModelAnovaModel::mimeDataMoved(const QModelIndexList &indexes)
{
	// sort indices, and delete from end to beginning

	QModelIndexList sorted = indexes;
	qSort(sorted.begin(), sorted.end(), qGreater<QModelIndex>());

	int lastRowDeleted = -1;

	Terms terms = _terms;

	foreach (const QModelIndex &index, sorted)
	{
		int rowNo = index.row();
		if (rowNo != lastRowDeleted)
			terms.remove(index.row());
		lastRowDeleted = rowNo;
	}

	setTerms(terms);
}

const Terms &TableModelAnovaModel::terms() const
{
	return _terms;
}

void TableModelAnovaModel::addFixedFactors(const Terms &terms)
{
	_fixedFactors.add(terms);
	_variables.add(terms);

	Terms existingTerms = _terms;

	Terms newTerms = _terms;
	newTerms.discardWhatDoesContainTheseComponents(_randomFactors);
	newTerms.discardWhatDoesContainTheseComponents(_covariates);
	existingTerms.add(newTerms.ffCombinations(terms));

	setTerms(existingTerms);

	emit variablesAvailableChanged();
}

void TableModelAnovaModel::addRandomFactors(const Terms &terms)
{
	_randomFactors.add(terms);
	_variables.add(terms);

	Terms newTerms = _terms;
	newTerms.add(terms);

	setTerms(newTerms, true);

	emit variablesAvailableChanged();
}

void TableModelAnovaModel::addCovariates(const Terms &terms)
{
	_covariates.add(terms);
	_variables.add(terms);

	Terms newTerms = _terms;
	newTerms.add(terms);

	setTerms(newTerms);

	emit variablesAvailableChanged();
}

void TableModelAnovaModel::removeVariables(const Terms &terms)
{
	_variables.remove(terms);
	_fixedFactors.remove(terms);
	_randomFactors.remove(terms);
	_covariates.remove(terms);

	Terms newTerms = _terms;
	newTerms.discardWhatDoesContainTheseComponents(terms);

	setTerms(newTerms);

	emit variablesAvailableChanged();
}

bool TableModelAnovaModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
	Q_UNUSED(action);
	Q_UNUSED(row);
	Q_UNUSED(column);
	Q_UNUSED(parent);

	if (mimeTypes().contains("application/vnd.list.term"))
	{
		QByteArray encodedData = data->data("application/vnd.list.term");
		QDataStream stream(&encodedData, QIODevice::ReadOnly);

		if (stream.atEnd())
			return false;

		return true;
	}

	return false;
}

bool TableModelAnovaModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent, int assignType)
{
	if (action == Qt::IgnoreAction)
		return true;

	if ( ! canDropMimeData(data, action, row, column, parent))
		return false;

	if ( ! data->hasFormat("application/vnd.list.term"))
		return false;

	QByteArray encodedData = data->data("application/vnd.list.term");

	Terms dropped;
	dropped.setSortParent(_variables);
	dropped.set(encodedData);

	Terms newTerms;

	switch (assignType)
	{
	case Cross:
		newTerms = dropped.crossCombinations();
		break;
	case Interaction:
		newTerms = dropped.wayCombinations(dropped.size());
		break;
	case MainEffects:
		newTerms = dropped.wayCombinations(1);
		break;
	case All2Way:
		newTerms = dropped.wayCombinations(2);
		break;
	case All3Way:
		newTerms = dropped.wayCombinations(3);
		break;
	case All4Way:
		newTerms = dropped.wayCombinations(4);
		break;
	case All5Way:
		newTerms = dropped.wayCombinations(5);
		break;
	default:
		(void)newTerms;
	}

	assign(newTerms);

	return true;
}

bool TableModelAnovaModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
	return dropMimeData(data, action, row, column, parent, Cross);
}

QMimeData *TableModelAnovaModel::mimeData(const QModelIndexList &indexes) const
{
	/* returns dummy data. when the user drags entries away from this listbox
	 * it means that they're deleting entries, so there's no point populating
	 * this data object properly
	 */

	Q_UNUSED(indexes);

	QMimeData *mimeData = new QMimeData();
	QByteArray encodedData;

	QDataStream dataStream(&encodedData, QIODevice::WriteOnly);

	dataStream << 0;

	mimeData->setData("application/vnd.list.term", encodedData);

	return mimeData;
}

Qt::ItemFlags TableModelAnovaModel::flags(const QModelIndex &index) const
{
	if (index.isValid())
	{
		if (index.column() == 0)
			return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
		else
			return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
	}
	else
	{
		return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
	}
}

QVariant TableModelAnovaModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (orientation == Qt::Horizontal)
	{
		if (role == Qt::DisplayRole)
		{
			if (section == 0)
				return "Model Terms";
			else if (section == 1)
				return "Is Nuisance";
		}
		else
		{
			if (section == 1 && role == Qt::SizeHintRole)
				return QSize(50, -1);
		}
	}

	return QVariant();
}

Qt::DropActions TableModelAnovaModel::supportedDropActions() const
{
	return Qt::CopyAction;
}

Qt::DropActions TableModelAnovaModel::supportedDragActions() const
{
	return Qt::MoveAction;
}

OptionTerm *TableModelAnovaModel::termOptionFromRow(Options *row)
{
	return static_cast<OptionTerm *>(row->get(0));
}

void TableModelAnovaModel::setTerms(const Terms &terms, bool newTermsAreNuisance)
{
	_terms.set(terms);

	if (_boundTo == NULL)
		return;

	beginResetModel();

	Terms::const_iterator itr;
	vector<Options *>::iterator otr;

	otr = _rows.begin();

	while (otr != _rows.end())
	{
		Options *row = *otr;
		OptionTerm *termCell = termOptionFromRow(row);
		Term existingTerm = Term(termCell->term());

		bool shouldRemove = true;

		itr = terms.begin();

		while (itr != terms.end())
		{
			const Term &term = *itr;

			if (term == existingTerm)
			{
				shouldRemove = false;
				break;
			}

			itr++;
		}

		if (shouldRemove)
		{
			_rows.erase(otr);
			delete row;
		}
		else
		{
			otr++;
		}
	}

	itr = terms.begin();

	for (int i = 0; i < terms.size(); i++)
	{
		const Term &term = *itr;

		if (i < _rows.size())
		{
			otr = _rows.begin();
			otr += i;
			Options *row = *otr;
			OptionTerm *termCell = termOptionFromRow(row);
			Term existingTerm = Term(termCell->term());

			if (existingTerm != term)
			{
				Options *row = static_cast<Options *>(_boundTo->rowTemplate()->clone());
				OptionTerms *termCell = static_cast<OptionTerms *>(row->get(0));
				termCell->setValue(term.scomponents());

				if (row->size() > 1 && newTermsAreNuisance)
				{
					OptionBoolean *nuisance = static_cast<OptionBoolean *>(row->get(1));
					nuisance->setValue(true);
				}

				_rows.insert(otr, row);
			}
		}
		else
		{
			Options *row = static_cast<Options *>(_boundTo->rowTemplate()->clone());
			OptionTerms *termCell = static_cast<OptionTerms *>(row->get(0));
			termCell->setValue(term.scomponents());

			if (row->size() > 1 && newTermsAreNuisance)
			{
				OptionBoolean *nuisance = static_cast<OptionBoolean *>(row->get(1));
				nuisance->setValue(true);
			}

			_rows.push_back(row);
		}

		itr++;
	}

	updateNuisances();

	_boundTo->setValue(_rows);

	endResetModel();

	emit termsChanged();
}

void TableModelAnovaModel::clear()
{
	setTerms(Terms());
}

void TableModelAnovaModel::assign(const Terms &terms)
{
	Terms t = _terms;
	t.add(terms);
	setTerms(t);
}

void TableModelAnovaModel::updateNuisances(bool checked)
{
	// if a higher order interaction is specified as nuisance, then all lower order terms should be changed to nuisance as well

	for (int i = 0; i < _rows.size(); i++)
	{
		Options *row = _rows.at(i);
		OptionTerm *termOption = static_cast<OptionTerm*>(row->get(0));
		OptionBoolean *nuisanceOption = static_cast<OptionBoolean*>(row->get(1));
		Term term = Term(termOption->term());

		if (nuisanceOption->value() == checked)
		{
			for (int j = 0; j < _rows.size(); j++)
			{
				if (i == j)
					continue;

				Options *r = _rows.at(j);

				OptionTerm *tOption = static_cast<OptionTerm*>(r->get(0));
				OptionBoolean *nOption = static_cast<OptionBoolean*>(r->get(1));
				Term t = Term(tOption->term());

				if (checked)
				{
					if (term.containsAll(t))
						nOption->setValue(true);
				}
				else
				{
					if (t.containsAll(term))
						nOption->setValue(false);
				}
			}
		}
	}

	emit dataChanged(this->index(0,1), this->index(_rows.size() - 1, 1));
}
<|endoftext|>


<commit_before>/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImageDecoder.h"
#include "SkBitmap.h"
#include "SkImagePriv.h"
#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkCanvas.h"

SkImageDecoder::SkImageDecoder()
    : fPeeker(NULL)
#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
    , fChooser(NULL)
#endif
    , fAllocator(NULL)
    , fSampleSize(1)
    , fDefaultPref(kUnknown_SkColorType)
    , fDitherImage(true)
#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG
    , fUsePrefTable(false)
#endif
    , fSkipWritingZeroes(false)
    , fPreferQualityOverSpeed(false)
    , fRequireUnpremultipliedColors(false) {
}

SkImageDecoder::~SkImageDecoder() {
    SkSafeUnref(fPeeker);
#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
    SkSafeUnref(fChooser);
#endif
    SkSafeUnref(fAllocator);
}

void SkImageDecoder::copyFieldsToOther(SkImageDecoder* other) {
    if (NULL == other) {
        return;
    }
    other->setPeeker(fPeeker);
#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
    other->setChooser(fChooser);
#endif
    other->setAllocator(fAllocator);
    other->setSampleSize(fSampleSize);
#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG
    if (fUsePrefTable) {
        other->setPrefConfigTable(fPrefTable);
    } else {
        other->fDefaultPref = fDefaultPref;
    }
#endif
    other->setDitherImage(fDitherImage);
    other->setSkipWritingZeroes(fSkipWritingZeroes);
    other->setPreferQualityOverSpeed(fPreferQualityOverSpeed);
    other->setRequireUnpremultipliedColors(fRequireUnpremultipliedColors);
}

SkImageDecoder::Format SkImageDecoder::getFormat() const {
    return kUnknown_Format;
}

const char* SkImageDecoder::getFormatName() const {
    return GetFormatName(this->getFormat());
}

const char* SkImageDecoder::GetFormatName(Format format) {
    switch (format) {
        case kUnknown_Format:
            return "Unknown Format";
        case kBMP_Format:
            return "BMP";
        case kGIF_Format:
            return "GIF";
        case kICO_Format:
            return "ICO";
        case kPKM_Format:
            return "PKM";
        case kKTX_Format:
            return "KTX";
        case kJPEG_Format:
            return "JPEG";
        case kPNG_Format:
            return "PNG";
        case kWBMP_Format:
            return "WBMP";
        case kWEBP_Format:
            return "WEBP";
        default:
            SkDEBUGFAIL("Invalid format type!");
    }
    return "Unknown Format";
}

SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
    SkRefCnt_SafeAssign(fPeeker, peeker);
    return peeker;
}

#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
    SkRefCnt_SafeAssign(fChooser, chooser);
    return chooser;
}
#endif

SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
    SkRefCnt_SafeAssign(fAllocator, alloc);
    return alloc;
}

void SkImageDecoder::setSampleSize(int size) {
    if (size < 1) {
        size = 1;
    }
    fSampleSize = size;
}

#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
// TODO: change Chooser virtual to take colorType, so we can stop calling SkColorTypeToBitmapConfig
//
bool SkImageDecoder::chooseFromOneChoice(SkColorType colorType, int width, int height) const {
    Chooser* chooser = fChooser;

    if (NULL == chooser) {    // no chooser, we just say YES to decoding :)
        return true;
    }
    chooser->begin(1);
    chooser->inspect(0, SkColorTypeToBitmapConfig(colorType), width, height);
    return chooser->choose() == 0;
}
#endif

bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
                                   SkColorTable* ctable) const {
    return bitmap->allocPixels(fAllocator, ctable);
}

///////////////////////////////////////////////////////////////////////////////

#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG
void SkImageDecoder::setPrefConfigTable(const PrefConfigTable& prefTable) {
    fUsePrefTable = true;
    fPrefTable = prefTable;
}
#endif

// TODO: use colortype in fPrefTable, fDefaultPref so we can stop using SkBitmapConfigToColorType()
//
SkColorType SkImageDecoder::getPrefColorType(SrcDepth srcDepth, bool srcHasAlpha) const {
    SkColorType ct = fDefaultPref;
#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG

    if (fUsePrefTable) {
        // Until we kill or change the PrefTable, we have to go into Config land for a moment.
        SkBitmap::Config config = SkBitmap::kNo_Config;
        switch (srcDepth) {
            case kIndex_SrcDepth:
                config = srcHasAlpha ? fPrefTable.fPrefFor_8Index_YesAlpha_src
                                     : fPrefTable.fPrefFor_8Index_NoAlpha_src;
                break;
            case k8BitGray_SrcDepth:
                config = fPrefTable.fPrefFor_8Gray_src;
                break;
            case k32Bit_SrcDepth:
                config = srcHasAlpha ? fPrefTable.fPrefFor_8bpc_YesAlpha_src
                                     : fPrefTable.fPrefFor_8bpc_NoAlpha_src;
                break;
        }
        // now return to SkColorType land
        ct = SkBitmapConfigToColorType(config);
    }
#endif
    return ct;
}

SkImageDecoder::Result SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, SkColorType pref,
                                              Mode mode) {
    // we reset this to false before calling onDecode
    fShouldCancelDecode = false;
    // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
    fDefaultPref = pref;

    // pass a temporary bitmap, so that if we return false, we are assured of
    // leaving the caller's bitmap untouched.
    SkBitmap tmp;
    const Result result = this->onDecode(stream, &tmp, mode);
    if (kFailure != result) {
        bm->swap(tmp);
    }
    return result;
}

bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect, SkColorType pref) {
    // we reset this to false before calling onDecodeSubset
    fShouldCancelDecode = false;
    // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
    fDefaultPref = pref;

    return this->onDecodeSubset(bm, rect);
}

bool SkImageDecoder::buildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
    // we reset this to false before calling onBuildTileIndex
    fShouldCancelDecode = false;

    return this->onBuildTileIndex(stream, width, height);
}

bool SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
                                int dstX, int dstY, int width, int height,
                                int srcX, int srcY) {
    int w = width / sampleSize;
    int h = height / sampleSize;
    if (src->colorType() == kIndex_8_SkColorType) {
        // kIndex8 does not allow drawing via an SkCanvas, as is done below.
        // Instead, use extractSubset. Note that this shares the SkPixelRef and
        // SkColorTable.
        // FIXME: Since src is discarded in practice, this holds on to more
        // pixels than is strictly necessary. Switch to a copy if memory
        // savings are more important than speed here. This also means
        // that the pixels in dst can not be reused (though there is no
        // allocation, which was already done on src).
        int x = (dstX - srcX) / sampleSize;
        int y = (dstY - srcY) / sampleSize;
        SkIRect subset = SkIRect::MakeXYWH(x, y, w, h);
        return src->extractSubset(dst, subset);
    }
    // if the destination has no pixels then we must allocate them.
    if (dst->isNull()) {
        dst->setInfo(src->info().makeWH(w, h));

        if (!this->allocPixelRef(dst, NULL)) {
            SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
            return false;
        }
    }
    // check to see if the destination is large enough to decode the desired
    // region. If this assert fails we will just draw as much of the source
    // into the destination that we can.
    if (dst->width() < w || dst->height() < h) {
        SkDEBUGF(("SkImageDecoder::cropBitmap does not have a large enough bitmap.\n"));
    }

    // Set the Src_Mode for the paint to prevent transparency issue in the
    // dest in the event that the dest was being re-used.
    SkPaint paint;
    paint.setXfermodeMode(SkXfermode::kSrc_Mode);

    SkCanvas canvas(*dst);
    canvas.drawSprite(*src, (srcX - dstX) / sampleSize,
                            (srcY - dstY) / sampleSize,
                            &paint);
    return true;
}

///////////////////////////////////////////////////////////////////////////////

bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm, SkColorType pref,  Mode mode,
                                Format* format) {
    SkASSERT(file);
    SkASSERT(bm);

    SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(file));
    if (stream.get()) {
        if (SkImageDecoder::DecodeStream(stream, bm, pref, mode, format)) {
            bm->pixelRef()->setURI(file);
            return true;
        }
    }
    return false;
}

bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm, SkColorType pref,
                                  Mode mode, Format* format) {
    if (0 == size) {
        return false;
    }
    SkASSERT(buffer);

    SkMemoryStream  stream(buffer, size);
    return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
}

bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm, SkColorType pref,
                                  Mode mode, Format* format) {
    SkASSERT(stream);
    SkASSERT(bm);

    bool success = false;
    SkImageDecoder* codec = SkImageDecoder::Factory(stream);

    if (NULL != codec) {
        success = codec->decode(stream, bm, pref, mode);
        if (success && format) {
            *format = codec->getFormat();
            if (kUnknown_Format == *format) {
                if (stream->rewind()) {
                    *format = GetStreamFormat(stream);
                }
            }
        }
        delete codec;
    }
    return success;
}
<commit_msg>skia: add compat SkImageDecoder::DecodeStream symbol<commit_after>/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImageDecoder.h"
#include "SkBitmap.h"
#include "SkImagePriv.h"
#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkCanvas.h"

SkImageDecoder::SkImageDecoder()
    : fPeeker(NULL)
#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
    , fChooser(NULL)
#endif
    , fAllocator(NULL)
    , fSampleSize(1)
    , fDefaultPref(kUnknown_SkColorType)
    , fDitherImage(true)
#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG
    , fUsePrefTable(false)
#endif
    , fSkipWritingZeroes(false)
    , fPreferQualityOverSpeed(false)
    , fRequireUnpremultipliedColors(false) {
}

SkImageDecoder::~SkImageDecoder() {
    SkSafeUnref(fPeeker);
#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
    SkSafeUnref(fChooser);
#endif
    SkSafeUnref(fAllocator);
}

void SkImageDecoder::copyFieldsToOther(SkImageDecoder* other) {
    if (NULL == other) {
        return;
    }
    other->setPeeker(fPeeker);
#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
    other->setChooser(fChooser);
#endif
    other->setAllocator(fAllocator);
    other->setSampleSize(fSampleSize);
#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG
    if (fUsePrefTable) {
        other->setPrefConfigTable(fPrefTable);
    } else {
        other->fDefaultPref = fDefaultPref;
    }
#endif
    other->setDitherImage(fDitherImage);
    other->setSkipWritingZeroes(fSkipWritingZeroes);
    other->setPreferQualityOverSpeed(fPreferQualityOverSpeed);
    other->setRequireUnpremultipliedColors(fRequireUnpremultipliedColors);
}

SkImageDecoder::Format SkImageDecoder::getFormat() const {
    return kUnknown_Format;
}

const char* SkImageDecoder::getFormatName() const {
    return GetFormatName(this->getFormat());
}

const char* SkImageDecoder::GetFormatName(Format format) {
    switch (format) {
        case kUnknown_Format:
            return "Unknown Format";
        case kBMP_Format:
            return "BMP";
        case kGIF_Format:
            return "GIF";
        case kICO_Format:
            return "ICO";
        case kPKM_Format:
            return "PKM";
        case kKTX_Format:
            return "KTX";
        case kJPEG_Format:
            return "JPEG";
        case kPNG_Format:
            return "PNG";
        case kWBMP_Format:
            return "WBMP";
        case kWEBP_Format:
            return "WEBP";
        default:
            SkDEBUGFAIL("Invalid format type!");
    }
    return "Unknown Format";
}

SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
    SkRefCnt_SafeAssign(fPeeker, peeker);
    return peeker;
}

#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
    SkRefCnt_SafeAssign(fChooser, chooser);
    return chooser;
}
#endif

SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
    SkRefCnt_SafeAssign(fAllocator, alloc);
    return alloc;
}

void SkImageDecoder::setSampleSize(int size) {
    if (size < 1) {
        size = 1;
    }
    fSampleSize = size;
}

#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
// TODO: change Chooser virtual to take colorType, so we can stop calling SkColorTypeToBitmapConfig
//
bool SkImageDecoder::chooseFromOneChoice(SkColorType colorType, int width, int height) const {
    Chooser* chooser = fChooser;

    if (NULL == chooser) {    // no chooser, we just say YES to decoding :)
        return true;
    }
    chooser->begin(1);
    chooser->inspect(0, SkColorTypeToBitmapConfig(colorType), width, height);
    return chooser->choose() == 0;
}
#endif

bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
                                   SkColorTable* ctable) const {
    return bitmap->allocPixels(fAllocator, ctable);
}

///////////////////////////////////////////////////////////////////////////////

#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG
void SkImageDecoder::setPrefConfigTable(const PrefConfigTable& prefTable) {
    fUsePrefTable = true;
    fPrefTable = prefTable;
}
#endif

// TODO: use colortype in fPrefTable, fDefaultPref so we can stop using SkBitmapConfigToColorType()
//
SkColorType SkImageDecoder::getPrefColorType(SrcDepth srcDepth, bool srcHasAlpha) const {
    SkColorType ct = fDefaultPref;
#ifdef SK_SUPPORT_LEGACY_BITMAP_CONFIG

    if (fUsePrefTable) {
        // Until we kill or change the PrefTable, we have to go into Config land for a moment.
        SkBitmap::Config config = SkBitmap::kNo_Config;
        switch (srcDepth) {
            case kIndex_SrcDepth:
                config = srcHasAlpha ? fPrefTable.fPrefFor_8Index_YesAlpha_src
                                     : fPrefTable.fPrefFor_8Index_NoAlpha_src;
                break;
            case k8BitGray_SrcDepth:
                config = fPrefTable.fPrefFor_8Gray_src;
                break;
            case k32Bit_SrcDepth:
                config = srcHasAlpha ? fPrefTable.fPrefFor_8bpc_YesAlpha_src
                                     : fPrefTable.fPrefFor_8bpc_NoAlpha_src;
                break;
        }
        // now return to SkColorType land
        ct = SkBitmapConfigToColorType(config);
    }
#endif
    return ct;
}

SkImageDecoder::Result SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, SkColorType pref,
                                              Mode mode) {
    // we reset this to false before calling onDecode
    fShouldCancelDecode = false;
    // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
    fDefaultPref = pref;

    // pass a temporary bitmap, so that if we return false, we are assured of
    // leaving the caller's bitmap untouched.
    SkBitmap tmp;
    const Result result = this->onDecode(stream, &tmp, mode);
    if (kFailure != result) {
        bm->swap(tmp);
    }
    return result;
}

bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect, SkColorType pref) {
    // we reset this to false before calling onDecodeSubset
    fShouldCancelDecode = false;
    // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
    fDefaultPref = pref;

    return this->onDecodeSubset(bm, rect);
}

bool SkImageDecoder::buildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
    // we reset this to false before calling onBuildTileIndex
    fShouldCancelDecode = false;

    return this->onBuildTileIndex(stream, width, height);
}

bool SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
                                int dstX, int dstY, int width, int height,
                                int srcX, int srcY) {
    int w = width / sampleSize;
    int h = height / sampleSize;
    if (src->colorType() == kIndex_8_SkColorType) {
        // kIndex8 does not allow drawing via an SkCanvas, as is done below.
        // Instead, use extractSubset. Note that this shares the SkPixelRef and
        // SkColorTable.
        // FIXME: Since src is discarded in practice, this holds on to more
        // pixels than is strictly necessary. Switch to a copy if memory
        // savings are more important than speed here. This also means
        // that the pixels in dst can not be reused (though there is no
        // allocation, which was already done on src).
        int x = (dstX - srcX) / sampleSize;
        int y = (dstY - srcY) / sampleSize;
        SkIRect subset = SkIRect::MakeXYWH(x, y, w, h);
        return src->extractSubset(dst, subset);
    }
    // if the destination has no pixels then we must allocate them.
    if (dst->isNull()) {
        dst->setInfo(src->info().makeWH(w, h));

        if (!this->allocPixelRef(dst, NULL)) {
            SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
            return false;
        }
    }
    // check to see if the destination is large enough to decode the desired
    // region. If this assert fails we will just draw as much of the source
    // into the destination that we can.
    if (dst->width() < w || dst->height() < h) {
        SkDEBUGF(("SkImageDecoder::cropBitmap does not have a large enough bitmap.\n"));
    }

    // Set the Src_Mode for the paint to prevent transparency issue in the
    // dest in the event that the dest was being re-used.
    SkPaint paint;
    paint.setXfermodeMode(SkXfermode::kSrc_Mode);

    SkCanvas canvas(*dst);
    canvas.drawSprite(*src, (srcX - dstX) / sampleSize,
                            (srcY - dstY) / sampleSize,
                            &paint);
    return true;
}

///////////////////////////////////////////////////////////////////////////////
#ifdef SK_SUPPORT_LEGACY_DECODEFILE
extern "C" bool _ZN14SkImageDecoder10DecodeFileEPKcP8SkBitmapNS2_6ConfigENS_4ModeEPNS_6FormatE(
    const char file[], SkBitmap* bm, SkBitmap::Config pref,
    SkImageDecoder::Mode mode, SkImageDecoder::Format* format) {

    SkColorType ct = SkBitmapConfigToColorType(pref);
    return SkImageDecoder::DecodeFile(file, bm, ct, mode, format);
}
#endif

bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm, SkColorType pref,  Mode mode,
                                Format* format) {
    SkASSERT(file);
    SkASSERT(bm);

    SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(file));
    if (stream.get()) {
        if (SkImageDecoder::DecodeStream(stream, bm, pref, mode, format)) {
            bm->pixelRef()->setURI(file);
            return true;
        }
    }
    return false;
}

bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm, SkColorType pref,
                                  Mode mode, Format* format) {
    if (0 == size) {
        return false;
    }
    SkASSERT(buffer);

    SkMemoryStream  stream(buffer, size);
    return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
}

bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm, SkColorType pref,
                                  Mode mode, Format* format) {
    SkASSERT(stream);
    SkASSERT(bm);

    bool success = false;
    SkImageDecoder* codec = SkImageDecoder::Factory(stream);

    if (NULL != codec) {
        success = codec->decode(stream, bm, pref, mode);
        if (success && format) {
            *format = codec->getFormat();
            if (kUnknown_Format == *format) {
                if (stream->rewind()) {
                    *format = GetStreamFormat(stream);
                }
            }
        }
        delete codec;
    }
    return success;
}
<|endoftext|>


<commit_before>#include "../include/oasis.h"
#ifdef HAVE_PARQUET
#include "../include/oasisparquet.h"
#endif

#include <cstring>
#include <map>
#include <vector>

namespace katparquet {

  template<typename tableNameT>
  void DoKat(const std::vector<std::string> &inFiles,
	     parquet::StreamWriter &osOut, std::vector<tableNameT> &rows) {

    rows.resize(inFiles.size());
    std::vector<parquet::StreamReader> isIn;
    isIn.resize(inFiles.size());
    std::map<int, int> event_to_file;

    // Read first row from each file
    for (int i = 0; i < (int)inFiles.size(); i++) {
      isIn[i] = OasisParquet::SetupParquetInputStream(inFiles[i]);
      tableNameT row;
      if (isIn[i].eof()) continue;   // Ignore empty files
      isIn[i] >> row;
      rows[i] = row;

      event_to_file[rows[i].eventID] = i;
    }

    if (event_to_file.size() == 0) {
      fprintf(stderr, "ERROR: All input files are empty\n");
      exit(EXIT_FAILURE);
    }

    // First entry should always have lowest event ID
    while(event_to_file.size() != 0) {

      auto iter = event_to_file.begin();
      int currentEventID = iter->first;

      while (rows[iter->second].eventID == currentEventID) {
	osOut << rows[iter->second];
	if (isIn[iter->second].eof()) break;
	isIn[iter->second] >> rows[iter->second];
      }

      if (!isIn[iter->second].eof()) {
	event_to_file[rows[iter->second].eventID] = iter->second;
      }

      event_to_file.erase(iter);

    }

  }

  void doit(const std::vector<std::string> &inFiles,
	    const std::string outFile, const int tableName) {

    parquet::StreamWriter osOut = OasisParquet::GetParquetStreamWriter(tableName, outFile);

    if (tableName == OasisParquet::MPLT) {
      std::vector<OasisParquet::MomentPLTEntry> rows;
      DoKat(inFiles, osOut, rows);
    } else if (tableName == OasisParquet::QPLT) {
      std::vector<OasisParquet::QuantilePLTEntry> rows;
      DoKat(inFiles, osOut, rows);
    } else if (tableName == OasisParquet::SPLT) {
      std::vector<OasisParquet::SamplePLTEntry> rows;
      DoKat(inFiles, osOut, rows);
    } else if (tableName == OasisParquet::MELT) {
      std::vector<OasisParquet::MomentELTEntry> rows;
      DoKat(inFiles, osOut, rows);
    } else if (tableName == OasisParquet::QELT) {
      std::vector<OasisParquet::QuantileELTEntry> rows;
      DoKat(inFiles, osOut, rows);
    } else if (tableName == OasisParquet::SELT) {
      std::vector<OasisParquet::SampleELTEntry> rows;
      DoKat(inFiles, osOut, rows);
    } else if (tableName == OasisParquet::NONE) {
      fprintf(stderr, "FATAL: No table type selected - please select table "
		      "type for files to be concatenated.\n");
      exit(EXIT_FAILURE);
    } else {   // Should never get here
      fprintf(stderr, "FATAL: Unknown table selected.\n");
      exit(EXIT_FAILURE);
    }

  }

}
<commit_msg>Sort Period Loss Tables by period number and then event ID (#298)<commit_after>#include "../include/oasis.h"
#ifdef HAVE_PARQUET
#include "../include/oasisparquet.h"
#endif

#include <cstring>
#include <map>
#include <vector>

namespace katparquet {

  struct period_event {
    int period;
    int eventID;
  };

  bool operator<(const period_event &lhs, const period_event &rhs) {
    if (lhs.period != rhs.period) {
      return lhs.period < rhs.period;
    } else {
      return lhs.eventID < rhs.eventID;
    }
  }

  bool operator==(const period_event &lhs, const period_event &rhs) {
    return lhs.period == rhs.period && lhs.eventID == rhs.eventID;
  }

  template<typename tableNameT>
  void GetRow(std::map<int, int> &event_to_file, const tableNameT &row,
	      const int i) {
    event_to_file[row.eventID] = i;
  }

  template<typename tableNameT>
  void GetRow(std::map<period_event, int> &period_to_file,
	      const tableNameT &row, const int i) {
    period_event periodEventID;
    periodEventID.period = row.period;
    periodEventID.eventID = row.eventID;
    period_to_file[periodEventID] = i;
  }

  template<typename tableNameT, typename rowMapT>
  void ReadFirstRows(const std::vector<std::string> &inFiles,
		     std::vector<parquet::StreamReader> &isIn,
		     std::vector<tableNameT> &rows, rowMapT &rowMap_to_file) {

    // Read first row from each file
    for (int i = 0; i < (int)inFiles.size(); i++) {
      isIn[i] = OasisParquet::SetupParquetInputStream(inFiles[i]);
      tableNameT row;
      if (isIn[i].eof()) continue;   // Ignore empty files
      isIn[i] >> row;
      rows[i] = row;

      GetRow(rowMap_to_file, rows[i], i);
    }

  }

  template<typename tableNameT>
  void WriteOutput(std::vector<tableNameT> &rows,
		   std::map<int, int> &event_to_file,
		   parquet::StreamWriter &osOut,
		   std::vector<parquet::StreamReader> &isIn) {

    // First entry should always have lowest event ID
    while(event_to_file.size() != 0) {

      auto iter = event_to_file.begin();
      int currentEventID = iter->first;

      while (rows[iter->second].eventID == currentEventID) {
	osOut << rows[iter->second];
	if (isIn[iter->second].eof()) break;
	isIn[iter->second] >> rows[iter->second];
      }

      if (!isIn[iter->second].eof()) {
	GetRow(event_to_file, rows[iter->second], iter->second);
      }

      event_to_file.erase(iter);

    }

  }

  template<typename tableNameT>
  void WriteOutput(std::vector<tableNameT> &rows,
		   std::map<period_event, int> &period_to_file,
		   parquet::StreamWriter &osOut,
		   std::vector<parquet::StreamReader> &isIn) {

    // First entry should always have lowest period number followed by event ID
    while (period_to_file.size() != 0) {

      auto iter = period_to_file.begin();
      period_event currentPeriodEvent = iter->first;
      period_event periodEventID;
      periodEventID.period = rows[iter->second].period;
      periodEventID.eventID = rows[iter->second].eventID;

      while (periodEventID == currentPeriodEvent) {
	osOut << rows[iter->second];
	if (isIn[iter->second].eof()) break;
	isIn[iter->second] >> rows[iter->second];
	periodEventID.period = rows[iter->second].period;
	periodEventID.eventID = rows[iter->second].eventID;
      }

      if (!isIn[iter->second].eof()) {
	GetRow(period_to_file, rows[iter->second], iter->second);
      }

      period_to_file.erase(iter);

    }

  }

  template<typename tableNameT, typename rowMapT>
  void DoKat(const std::vector<std::string> &inFiles,
	     parquet::StreamWriter &osOut, std::vector<tableNameT> &rows,
	     rowMapT &rowMap_to_file) {

    rows.resize(inFiles.size());
    std::vector<parquet::StreamReader> isIn;
    isIn.resize(inFiles.size());

    ReadFirstRows(inFiles, isIn, rows, rowMap_to_file);

    if (rowMap_to_file.size() == 0) {
      fprintf(stderr, "ERROR: All input files are empty\n");
      exit(EXIT_FAILURE);
    }

    WriteOutput(rows, rowMap_to_file, osOut, isIn);

  }

  void doit(const std::vector<std::string> &inFiles,
	    const std::string outFile, const int tableName) {

    parquet::StreamWriter osOut = OasisParquet::GetParquetStreamWriter(tableName, outFile);
    std::map<int, int> event_to_file;   // Exceedance Loss Table
    std::map<period_event, int> period_to_file;   // Period Loss Table

    if (tableName == OasisParquet::MPLT) {
      std::vector<OasisParquet::MomentPLTEntry> rows;
      DoKat(inFiles, osOut, rows, period_to_file);
    } else if (tableName == OasisParquet::QPLT) {
      std::vector<OasisParquet::QuantilePLTEntry> rows;
      DoKat(inFiles, osOut, rows, period_to_file);
    } else if (tableName == OasisParquet::SPLT) {
      std::vector<OasisParquet::SamplePLTEntry> rows;
      DoKat(inFiles, osOut, rows, period_to_file);
    } else if (tableName == OasisParquet::MELT) {
      std::vector<OasisParquet::MomentELTEntry> rows;
      DoKat(inFiles, osOut, rows, event_to_file);
    } else if (tableName == OasisParquet::QELT) {
      std::vector<OasisParquet::QuantileELTEntry> rows;
      DoKat(inFiles, osOut, rows, event_to_file);
    } else if (tableName == OasisParquet::SELT) {
      std::vector<OasisParquet::SampleELTEntry> rows;
      DoKat(inFiles, osOut, rows, event_to_file);
    } else if (tableName == OasisParquet::NONE) {
      fprintf(stderr, "FATAL: No table type selected - please select table "
		      "type for files to be concatenated.\n");
      exit(EXIT_FAILURE);
    } else {   // Should never get here
      fprintf(stderr, "FATAL: Unknown table selected.\n");
      exit(EXIT_FAILURE);
    }

  }

}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008 Larry Gritz
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// (this is the MIT license)
/////////////////////////////////////////////////////////////////////////////

#include <cstdio>
#include <cstdlib>

#include <half.h>

#include <boost/algorithm/string.hpp>
using boost::algorithm::iequals;

#include "dassert.h"
#include "paramtype.h"

#define DLL_EXPORT_PUBLIC /* Because we are implementing ImageIO */
#include "imageio.h"
#undef DLL_EXPORT_PUBLIC

using namespace OpenImageIO;

// Generate the default quantization parameters, templated on the data
// type.
template <class T>
static void
set_default_quantize (int &quant_black, int &quant_white,
                      int &quant_min, int &quant_max, float &quant_dither)
{
    if (std::numeric_limits <T>::is_integer) {
        quant_black  = 0;
        quant_white  = (int) std::numeric_limits <T>::max();
        quant_min    = (int) std::numeric_limits <T>::min();
        quant_max    = (int) std::numeric_limits <T>::max();
        quant_dither = 0.5f;
    } else {
        quant_black  = 0;
        quant_white  = 0;
        quant_min    = 0;
        quant_max    = 0;
        quant_dither = 0.0f;
    }
}

// Given the format, set the default quantization parameters.
// Rely on the template version to make life easy.
static void
set_default_quantize (ParamBaseType format,
                      int &quant_black, int &quant_white,
                      int &quant_min, int &quant_max, float &quant_dither)
{
    switch (format) {
    case PT_INT8:
        set_default_quantize <char> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_UNKNOWN:
    case PT_UINT8:
        set_default_quantize <unsigned char> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_INT16:
        set_default_quantize <short> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_UINT16:
        set_default_quantize <unsigned short> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_INT:
        set_default_quantize <int> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_UINT:
        set_default_quantize <unsigned int> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_HALF:
        set_default_quantize <half> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_FLOAT:
        set_default_quantize <float> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_DOUBLE:
        set_default_quantize <double> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    default: ASSERT(0);
    }
}

QuantizationSpec
    QuantizationSpec::quantize_default (std::numeric_limits<stride_t>::min(),
                                        std::numeric_limits<stride_t>::min(),
                                        std::numeric_limits<stride_t>::min(),
                                        std::numeric_limits<stride_t>::min(),
                                        0);

QuantizationSpec::QuantizationSpec (ParamBaseType _type)
{
    set_default_quantize (_type, quant_black, quant_white,
                          quant_min, quant_max, quant_dither);
}

ImageSpec::ImageSpec (ParamBaseType format)
    : x(0), y(0), z(0), width(0), height(0), depth(1),
      full_width(0), full_height(0), full_depth(0),
      tile_width(0), tile_height(0), tile_depth(1),
      format(format), nchannels(0), alpha_channel(-1), z_channel(-1),
      linearity(UnknownLinearity), gamma(1)
{
    set_format (format);
}

ImageSpec::ImageSpec (int xres, int yres, int nchans, ParamBaseType format)
    : x(0), y(0), z(0), width(xres), height(yres), depth(1),
      full_width(xres), full_height(yres), full_depth(1),
      tile_width(0), tile_height(0), tile_depth(1),
      format(format), nchannels(nchans), alpha_channel(-1), z_channel(-1),
      linearity(UnknownLinearity), gamma(1)
{
    set_format (format);
    default_channel_names ();
}

void
ImageSpec::set_format (ParamBaseType fmt)
{
    format = fmt;
    set_default_quantize (fmt, quant_black, quant_white,
                          quant_min, quant_max, quant_dither);
}

ParamBaseType
ImageSpec::format_from_quantize (int quant_black, int quant_white,
                                 int quant_min, int quant_max)
{
    if (quant_black == 0 && quant_white == 0 &&
        quant_min == 0 && quant_max == 0) {
        // Per RenderMan and Gelato heuristics, if all quantization
        // values are zero, assume they want a float output.
        return PT_FLOAT;
    } else if (quant_min >= std::numeric_limits <unsigned char>::min() &&
               quant_max <= std::numeric_limits <unsigned char>::max()) {
        return PT_UINT8;
    } else if (quant_min >= std::numeric_limits <char>::min() &&
               quant_max <= std::numeric_limits <char>::max()) {
        return PT_INT8;
    } else if (quant_min >= std::numeric_limits <unsigned short>::min() &&
               quant_max <= std::numeric_limits <unsigned short>::max()) {
        return PT_UINT16;
    } else if (quant_min >= std::numeric_limits <short>::min() &&
               quant_max <= std::numeric_limits <short>::max()) {
        return PT_INT16;
    } else if (quant_min >= std::numeric_limits <int>::min() &&
               quant_max <= std::numeric_limits <int>::max()) {
        return PT_INT;
    } else if (quant_min >= std::numeric_limits <unsigned int>::min() &&
               quant_max <= std::numeric_limits <unsigned int>::max()) {
        return PT_UINT;
    } else {
        return PT_UNKNOWN;
    }
}

void
ImageSpec::default_channel_names ()
{
    channelnames.clear();
    alpha_channel = -1;
    z_channel = -1;
    switch (nchannels) {
    case 1:
        channelnames.push_back ("A");
        break;
    case 2:
        channelnames.push_back ("I");
        channelnames.push_back ("A");
        alpha_channel = 1;
        break;
    case 3:
        channelnames.push_back ("R");
        channelnames.push_back ("G");
        channelnames.push_back ("B");
        break;
    default:
        if (nchannels >= 1)
            channelnames.push_back ("R");
        if (nchannels >= 2)
            channelnames.push_back ("G");
        if (nchannels >= 3)
            channelnames.push_back ("B");
        if (nchannels >= 4) {
            channelnames.push_back ("A");
            alpha_channel = 3;
        }
        for (int c = 4;  c < nchannels;  ++c)
            channelnames.push_back (Strutil::format("channel%d", c));
        break;
    }
}

void
ImageSpec::attribute (const std::string &name, ParamBaseType type,
                      int nvalues, const void *value)
{
    // Don't allow duplicates
    ImageIOParameter *f = find_attribute (name);
    if (! f) {
        extra_attribs.resize (extra_attribs.size() + 1);
        f = &extra_attribs.back();
    }
    f->init (name, type, nvalues, value);
}

ImageIOParameter *
ImageSpec::find_attribute (const std::string &name, ParamType searchtype,
                           bool casesensitive)
{
    if (casesensitive) {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (extra_attribs[i].name() == name &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    } else {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (iequals (extra_attribs[i].name().string(), name) &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    }
    return NULL;
}

const ImageIOParameter *
ImageSpec::find_attribute (const std::string &name, ParamType searchtype,
                           bool casesensitive) const
{
    if (casesensitive) {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (extra_attribs[i].name() == name &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    } else {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (iequals (extra_attribs[i].name().string(), name) &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    }
    return NULL;
}
<commit_msg>Bug fix - needed to include strutil.h<commit_after>/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008 Larry Gritz
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// (this is the MIT license)
/////////////////////////////////////////////////////////////////////////////

#include <cstdio>
#include <cstdlib>

#include <half.h>

#include <boost/algorithm/string.hpp>
using boost::algorithm::iequals;

#include "dassert.h"
#include "paramtype.h"
#include "strutil.h"

#define DLL_EXPORT_PUBLIC /* Because we are implementing ImageIO */
#include "imageio.h"
#undef DLL_EXPORT_PUBLIC

using namespace OpenImageIO;

// Generate the default quantization parameters, templated on the data
// type.
template <class T>
static void
set_default_quantize (int &quant_black, int &quant_white,
                      int &quant_min, int &quant_max, float &quant_dither)
{
    if (std::numeric_limits <T>::is_integer) {
        quant_black  = 0;
        quant_white  = (int) std::numeric_limits <T>::max();
        quant_min    = (int) std::numeric_limits <T>::min();
        quant_max    = (int) std::numeric_limits <T>::max();
        quant_dither = 0.5f;
    } else {
        quant_black  = 0;
        quant_white  = 0;
        quant_min    = 0;
        quant_max    = 0;
        quant_dither = 0.0f;
    }
}

// Given the format, set the default quantization parameters.
// Rely on the template version to make life easy.
static void
set_default_quantize (ParamBaseType format,
                      int &quant_black, int &quant_white,
                      int &quant_min, int &quant_max, float &quant_dither)
{
    switch (format) {
    case PT_INT8:
        set_default_quantize <char> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_UNKNOWN:
    case PT_UINT8:
        set_default_quantize <unsigned char> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_INT16:
        set_default_quantize <short> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_UINT16:
        set_default_quantize <unsigned short> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_INT:
        set_default_quantize <int> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_UINT:
        set_default_quantize <unsigned int> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_HALF:
        set_default_quantize <half> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_FLOAT:
        set_default_quantize <float> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    case PT_DOUBLE:
        set_default_quantize <double> (quant_black, quant_white,
                                     quant_min, quant_max, quant_dither);
        break;
    default: ASSERT(0);
    }
}

QuantizationSpec
    QuantizationSpec::quantize_default (std::numeric_limits<stride_t>::min(),
                                        std::numeric_limits<stride_t>::min(),
                                        std::numeric_limits<stride_t>::min(),
                                        std::numeric_limits<stride_t>::min(),
                                        0);

QuantizationSpec::QuantizationSpec (ParamBaseType _type)
{
    set_default_quantize (_type, quant_black, quant_white,
                          quant_min, quant_max, quant_dither);
}

ImageSpec::ImageSpec (ParamBaseType format)
    : x(0), y(0), z(0), width(0), height(0), depth(1),
      full_width(0), full_height(0), full_depth(0),
      tile_width(0), tile_height(0), tile_depth(1),
      format(format), nchannels(0), alpha_channel(-1), z_channel(-1),
      linearity(UnknownLinearity), gamma(1)
{
    set_format (format);
}

ImageSpec::ImageSpec (int xres, int yres, int nchans, ParamBaseType format)
    : x(0), y(0), z(0), width(xres), height(yres), depth(1),
      full_width(xres), full_height(yres), full_depth(1),
      tile_width(0), tile_height(0), tile_depth(1),
      format(format), nchannels(nchans), alpha_channel(-1), z_channel(-1),
      linearity(UnknownLinearity), gamma(1)
{
    set_format (format);
    default_channel_names ();
}

void
ImageSpec::set_format (ParamBaseType fmt)
{
    format = fmt;
    set_default_quantize (fmt, quant_black, quant_white,
                          quant_min, quant_max, quant_dither);
}

ParamBaseType
ImageSpec::format_from_quantize (int quant_black, int quant_white,
                                 int quant_min, int quant_max)
{
    if (quant_black == 0 && quant_white == 0 &&
        quant_min == 0 && quant_max == 0) {
        // Per RenderMan and Gelato heuristics, if all quantization
        // values are zero, assume they want a float output.
        return PT_FLOAT;
    } else if (quant_min >= std::numeric_limits <unsigned char>::min() &&
               quant_max <= std::numeric_limits <unsigned char>::max()) {
        return PT_UINT8;
    } else if (quant_min >= std::numeric_limits <char>::min() &&
               quant_max <= std::numeric_limits <char>::max()) {
        return PT_INT8;
    } else if (quant_min >= std::numeric_limits <unsigned short>::min() &&
               quant_max <= std::numeric_limits <unsigned short>::max()) {
        return PT_UINT16;
    } else if (quant_min >= std::numeric_limits <short>::min() &&
               quant_max <= std::numeric_limits <short>::max()) {
        return PT_INT16;
    } else if (quant_min >= std::numeric_limits <int>::min() &&
               quant_max <= std::numeric_limits <int>::max()) {
        return PT_INT;
    } else if (quant_min >= std::numeric_limits <unsigned int>::min() &&
               quant_max <= std::numeric_limits <unsigned int>::max()) {
        return PT_UINT;
    } else {
        return PT_UNKNOWN;
    }
}

void
ImageSpec::default_channel_names ()
{
    channelnames.clear();
    alpha_channel = -1;
    z_channel = -1;
    switch (nchannels) {
    case 1:
        channelnames.push_back ("A");
        break;
    case 2:
        channelnames.push_back ("I");
        channelnames.push_back ("A");
        alpha_channel = 1;
        break;
    case 3:
        channelnames.push_back ("R");
        channelnames.push_back ("G");
        channelnames.push_back ("B");
        break;
    default:
        if (nchannels >= 1)
            channelnames.push_back ("R");
        if (nchannels >= 2)
            channelnames.push_back ("G");
        if (nchannels >= 3)
            channelnames.push_back ("B");
        if (nchannels >= 4) {
            channelnames.push_back ("A");
            alpha_channel = 3;
        }
        for (int c = 4;  c < nchannels;  ++c)
            channelnames.push_back (Strutil::format("channel%d", c));
        break;
    }
}

void
ImageSpec::attribute (const std::string &name, ParamBaseType type,
                      int nvalues, const void *value)
{
    // Don't allow duplicates
    ImageIOParameter *f = find_attribute (name);
    if (! f) {
        extra_attribs.resize (extra_attribs.size() + 1);
        f = &extra_attribs.back();
    }
    f->init (name, type, nvalues, value);
}

ImageIOParameter *
ImageSpec::find_attribute (const std::string &name, ParamType searchtype,
                           bool casesensitive)
{
    if (casesensitive) {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (extra_attribs[i].name() == name &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    } else {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (iequals (extra_attribs[i].name().string(), name) &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    }
    return NULL;
}

const ImageIOParameter *
ImageSpec::find_attribute (const std::string &name, ParamType searchtype,
                           bool casesensitive) const
{
    if (casesensitive) {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (extra_attribs[i].name() == name &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    } else {
        for (size_t i = 0;  i < extra_attribs.size();  ++i)
            if (iequals (extra_attribs[i].name().string(), name) &&
                (searchtype == PT_UNKNOWN || searchtype == extra_attribs[i].type()))
                return &extra_attribs[i];
    }
    return NULL;
}
<|endoftext|>


<commit_before><commit_msg>Fix #1039 (#1040)<commit_after><|endoftext|>