<commit_before>#include "master.hpp"

namespace factor {

// Simple non-optimizing compiler.

// This is one of the two compilers implementing Factor; the second one is
// written in Factor and performs advanced optimizations. See
// basis/compiler/compiler.factor.

// The non-optimizing compiler compiles a quotation at a time by
// concatenating machine code chunks; prolog, epilog, call word, jump to
// word, etc. These machine code chunks are generated from Factor code in
// basis/bootstrap/assembler/.

// Calls to words and constant quotations (referenced by conditionals and
// dips) are direct jumps to machine code blocks. Literals are also
// referenced directly without going through the literal table.

// It actually does do a little bit of very simple optimization:

// 1) Tail call optimization.

// 2) If a quotation is determined to not call any other words (except for a
// few special words which are open-coded, see below), then no prolog/epilog
// is generated.

// 3) When in tail position and immediately preceded by literal arguments,
// the 'if' is generated inline, instead of as a call to the 'if' word.

// 4) When preceded by a quotation, calls to 'dip', '2dip' and '3dip' are
// open-coded as retain stack manipulation surrounding a subroutine call.

// 5) Sub-primitives are primitive words which are implemented in assembly
// and not in the VM. They are open-coded and no subroutine call is generated.
// This includes stack shufflers, some fixnum arithmetic words, and words
// such as tag, slot and eq?. A primitive call is relatively expensive
// (two subroutine calls) so this results in a big speedup for relatively
// little effort.

inline cell quotation_jit::nth(cell index) {
  return array_nth(elements.untagged(), index);
}

void quotation_jit::init_quotation(cell quot) {
  elements = untag<quotation>(quot)->array;
}

bool quotation_jit::fast_if_p(cell i, cell length) {
  return (i + 3) == length &&
      (tagged<object>(array_nth(elements.untagged(), i + 1)).type() == QUOTATION_TYPE) &&
      array_nth(elements.untagged(), i + 2) == parent->special_objects[JIT_IF_WORD];
}

bool quotation_jit::primitive_call_p(cell i, cell length) {
  return (i + 2) <= length && array_nth(elements.untagged(), i + 1) ==
      parent->special_objects[JIT_PRIMITIVE_WORD];
}

bool quotation_jit::fast_dip_p(cell i, cell length) {
  return (i + 2) <= length && array_nth(elements.untagged(), i + 1) ==
      parent->special_objects[JIT_DIP_WORD];
}

bool quotation_jit::fast_2dip_p(cell i, cell length) {
  return (i + 2) <= length && array_nth(elements.untagged(), i + 1) ==
      parent->special_objects[JIT_2DIP_WORD];
}

bool quotation_jit::fast_3dip_p(cell i, cell length) {
  return (i + 2) <= length && array_nth(elements.untagged(), i + 1) ==
      parent->special_objects[JIT_3DIP_WORD];
}

bool quotation_jit::declare_p(cell i, cell length) {
  return (i + 2) <= length && array_nth(elements.untagged(), i + 1) ==
      parent->special_objects[JIT_DECLARE_WORD];
}

bool quotation_jit::mega_lookup_p(cell i, cell length) {
  return (i + 4) <= length &&
      (tagged<object>(array_nth(elements.untagged(), i + 1)).type() == FIXNUM_TYPE) &&
      (tagged<object>(array_nth(elements.untagged(), i + 2)).type() == ARRAY_TYPE) &&
      array_nth(elements.untagged(), i + 3) == parent->special_objects[MEGA_LOOKUP_WORD];
}

// Subprimitives should be flagged with whether they require a stack frame.
// See #295.
bool quotation_jit::special_subprimitive_p(cell obj) {
  return obj == parent->special_objects[SIGNAL_HANDLER_WORD] ||
         obj == parent->special_objects[LEAF_SIGNAL_HANDLER_WORD] ||
         obj == parent->special_objects[UNWIND_NATIVE_FRAMES_WORD];
}

// All quotations wants a stack frame, except if they contain:
//   1) calls to the special subprimitives, see #295.
//   2) mega cache lookups, see #651
bool quotation_jit::stack_frame_p() {
  cell length = array_capacity(elements.untagged());
  for (cell i = 0; i < length; i++) {
    cell obj = array_nth(elements.untagged(), i);
    cell tag = tagged<object>(obj).type();
    if ((tag == WORD_TYPE && special_subprimitive_p(obj)) ||
        (tag == ARRAY_TYPE && mega_lookup_p(i, length)))
      return false;
  }
  return true;
}

static bool trivial_quotation_p(array* elements) {
  return array_capacity(elements) == 1 &&
      TAG(array_nth(elements, 0)) == WORD_TYPE;
}

// Allocates memory (emit)
void quotation_jit::emit_epilog(bool needed) {
  if (needed) {
    emit(parent->special_objects[JIT_SAFEPOINT]);
    emit(parent->special_objects[JIT_EPILOG]);
  }
}

// Allocates memory conditionally
void quotation_jit::emit_quotation(cell quot_) {
  data_root<quotation> quot(quot_, parent);

  array* elements = untag<array>(quot->array);

  // If the quotation consists of a single word, compile a direct call
  // to the word.
  if (trivial_quotation_p(elements))
    literal(array_nth(elements, 0));
  else {
    if (compiling)
      parent->jit_compile_quotation(quot.value(), relocate);
    literal(quot.value());
  }
}

// Allocates memory (parameter(), literal(), emit_epilog, emit_with_literal)
void quotation_jit::iterate_quotation() {
  bool stack_frame = stack_frame_p();

  set_position(0);

  if (stack_frame) {
    emit(parent->special_objects[JIT_SAFEPOINT]);
    emit(parent->special_objects[JIT_PROLOG]);
  }

  cell length = array_capacity(elements.untagged());
  bool tail_call = false;

  for (cell i = 0; i < length; i++) {
    set_position(i);
    data_root<object> obj(nth(i), parent);

    switch (obj.type()) {
      case WORD_TYPE:
        // Sub-primitives
        if (to_boolean(obj.as<word>()->subprimitive)) {
          tail_call = emit_subprimitive(obj.value(),     // word
                                        i == length - 1, // tail_call_p
                                        stack_frame);    // stack_frame_p
        }                                                // Everything else
        else if (i == length - 1) {
          emit_epilog(stack_frame);
          tail_call = true;
          word_jump(obj.value());
        } else
          word_call(obj.value());
        break;
      case WRAPPER_TYPE:
        push(obj.as<wrapper>()->object);
        break;
      case BYTE_ARRAY_TYPE:
        // Primitive calls
        if (primitive_call_p(i, length)) {
// On x86-64 and PowerPC, the VM pointer is stored in a register;
// on other platforms, the RT_VM relocation is used and it needs
// an offset parameter
#ifdef FACTOR_X86
          parameter(tag_fixnum(0));
#endif
          parameter(obj.value());
          parameter(false_object);
#ifdef FACTOR_PPC_TOC
          parameter(obj.value());
          parameter(false_object);
#endif
          emit(parent->special_objects[JIT_PRIMITIVE]);

          i++;
        } else
          push(obj.value());
        break;
      case QUOTATION_TYPE:
        // 'if' preceded by two literal quotations (this is why if and ? are
        // mutually recursive in the library, but both still work)
        if (fast_if_p(i, length)) {
          emit_epilog(stack_frame);
          tail_call = true;
          emit_quotation(nth(i));
          emit_quotation(nth(i + 1));
          emit(parent->special_objects[JIT_IF]);
          i += 2;
        } // dip
        else if (fast_dip_p(i, length)) {
          emit_quotation(obj.value());
          emit(parent->special_objects[JIT_DIP]);
          i++;
        } // 2dip
        else if (fast_2dip_p(i, length)) {
          emit_quotation(obj.value());
          emit(parent->special_objects[JIT_2DIP]);
          i++;
        } // 3dip
        else if (fast_3dip_p(i, length)) {
          emit_quotation(obj.value());
          emit(parent->special_objects[JIT_3DIP]);
          i++;
        } else
          push(obj.value());
        break;
      case ARRAY_TYPE:
        // Method dispatch
        if (mega_lookup_p(i, length)) {
          tail_call = true;
          emit_mega_cache_lookup(nth(i), untag_fixnum(nth(i + 1)), nth(i + 2));
          i += 3;
        } // Non-optimizing compiler ignores declarations
        else if (declare_p(i, length))
          i++;
        else
          push(obj.value());
        break;
      default:
        push(obj.value());
        break;
    }
  }

  if (!tail_call) {
    set_position(length);
    emit_epilog(stack_frame);
    emit(parent->special_objects[JIT_RETURN]);
  }
}

cell quotation_jit::word_stack_frame_size(cell obj) {
  if (special_subprimitive_p(obj))
    return SIGNAL_HANDLER_STACK_FRAME_SIZE;
  return JIT_FRAME_SIZE;
}

// Allocates memory
void quotation_jit::emit_mega_cache_lookup(cell methods_, fixnum index,
                                           cell cache_) {
  data_root<array> methods(methods_, parent);
  data_root<array> cache(cache_, parent);

  // Load the object from the datastack.
  emit_with_literal(parent->special_objects[PIC_LOAD],
                    tag_fixnum(-index * sizeof(cell)));

  // Do a cache lookup.
  emit_with_literal(parent->special_objects[MEGA_LOOKUP], cache.value());

  // If we end up here, the cache missed.
  emit(parent->special_objects[JIT_PROLOG]);

  // Push index, method table and cache on the stack.
  push(methods.value());
  push(tag_fixnum(index));
  push(cache.value());
  word_call(parent->special_objects[MEGA_MISS_WORD]);

  // Now the new method has been stored into the cache, and its on
  // the stack.
  emit(parent->special_objects[JIT_EPILOG]);
  emit(parent->special_objects[JIT_EXECUTE]);
}

// Allocates memory
code_block* factor_vm::jit_compile_quotation(cell owner_, cell quot_,
                                             bool relocating) {
  data_root<object> owner(owner_, this);
  data_root<quotation> quot(quot_, this);

  quotation_jit compiler(owner.value(), true, relocating, this);
  compiler.init_quotation(quot.value());
  compiler.iterate_quotation();

  cell frame_size = compiler.word_stack_frame_size(owner_);

  code_block* compiled = compiler.to_code_block(CODE_BLOCK_UNOPTIMIZED,
                                                frame_size);
  if (relocating)
    initialize_code_block(compiled);

  return compiled;
}

// Allocates memory
void factor_vm::jit_compile_quotation(cell quot_, bool relocating) {
  data_root<quotation> quot(quot_, this);
  if (!quotation_compiled_p(quot.untagged())) {
    code_block* compiled =
        jit_compile_quotation(quot.value(), quot.value(), relocating);
    quot.untagged()->entry_point = compiled->entry_point();
  }
}

// Allocates memory
void factor_vm::primitive_jit_compile() {
  jit_compile_quotation(ctx->pop(), true);
}

cell factor_vm::lazy_jit_compile_entry_point() {
  return untag<word>(special_objects[LAZY_JIT_COMPILE_WORD])->entry_point;
}

// push a new quotation on the stack
// Allocates memory
void factor_vm::primitive_array_to_quotation() {
  quotation* quot = allot<quotation>(sizeof(quotation));

  quot->array = ctx->peek();
  quot->cached_effect = false_object;
  quot->cache_counter = false_object;
  quot->entry_point = lazy_jit_compile_entry_point();

  ctx->replace(tag<quotation>(quot));
}

// Allocates memory (from_unsigned_cell)
void factor_vm::primitive_quotation_code() {
  data_root<quotation> quot(ctx->pop(), this);

  ctx->push(from_unsigned_cell(quot->entry_point));
  ctx->push(from_unsigned_cell((cell)quot->code() + quot->code()->size()));
}

// Allocates memory
fixnum factor_vm::quot_code_offset_to_scan(cell quot_, cell offset) {
  data_root<quotation> quot(quot_, this);
  data_root<array> array(quot->array, this);

  quotation_jit compiler(quot.value(), false, false, this);
  compiler.init_quotation(quot.value());
  compiler.compute_position(offset);
  compiler.iterate_quotation();

  return compiler.get_position();
}

// Allocates memory
cell factor_vm::lazy_jit_compile(cell quot_) {
  data_root<quotation> quot(quot_, this);

  FACTOR_ASSERT(!quotation_compiled_p(quot.untagged()));

  code_block* compiled =
      jit_compile_quotation(quot.value(), quot.value(), true);
  quot.untagged()->entry_point = compiled->entry_point();

  return quot.value();
}

// Allocates memory
VM_C_API cell lazy_jit_compile(cell quot, factor_vm* parent) {
  return parent->lazy_jit_compile(quot);
}

bool factor_vm::quotation_compiled_p(quotation* quot) {
  return quot->entry_point != 0 &&
         quot->entry_point != lazy_jit_compile_entry_point();
}

void factor_vm::primitive_quotation_compiled_p() {
  quotation* quot = untag_check<quotation>(ctx->pop());
  ctx->push(tag_boolean(quotation_compiled_p(quot)));
}

}
<commit_msg>Revert "VM: undo a8aaa4288231a2395070c5b0ea4c43939bf81c63 (#1513)"<commit_after>#include "master.hpp"

namespace factor {

// Simple non-optimizing compiler.

// This is one of the two compilers implementing Factor; the second one is
// written in Factor and performs advanced optimizations. See
// basis/compiler/compiler.factor.

// The non-optimizing compiler compiles a quotation at a time by
// concatenating machine code chunks; prolog, epilog, call word, jump to
// word, etc. These machine code chunks are generated from Factor code in
// basis/bootstrap/assembler/.

// Calls to words and constant quotations (referenced by conditionals and
// dips) are direct jumps to machine code blocks. Literals are also
// referenced directly without going through the literal table.

// It actually does do a little bit of very simple optimization:

// 1) Tail call optimization.

// 2) If a quotation is determined to not call any other words (except for a
// few special words which are open-coded, see below), then no prolog/epilog
// is generated.

// 3) When in tail position and immediately preceded by literal arguments,
// the 'if' is generated inline, instead of as a call to the 'if' word.

// 4) When preceded by a quotation, calls to 'dip', '2dip' and '3dip' are
// open-coded as retain stack manipulation surrounding a subroutine call.

// 5) Sub-primitives are primitive words which are implemented in assembly
// and not in the VM. They are open-coded and no subroutine call is generated.
// This includes stack shufflers, some fixnum arithmetic words, and words
// such as tag, slot and eq?. A primitive call is relatively expensive
// (two subroutine calls) so this results in a big speedup for relatively
// little effort.

inline cell quotation_jit::nth(cell index) {
  return array_nth(elements.untagged(), index);
}

void quotation_jit::init_quotation(cell quot) {
  elements = untag<quotation>(quot)->array;
}

bool quotation_jit::fast_if_p(cell i, cell length) {
  return (i + 3) == length &&
      TAG(nth(i + 1)) == QUOTATION_TYPE &&
      nth(i + 2) == parent->special_objects[JIT_IF_WORD];
}

bool quotation_jit::primitive_call_p(cell i, cell length) {
  cell jit_primitive_word = parent->special_objects[JIT_PRIMITIVE_WORD];
  return (i + 2) <= length && nth(i + 1) == jit_primitive_word;
}

bool quotation_jit::fast_dip_p(cell i, cell length) {
  cell jit_dip_word = parent->special_objects[JIT_DIP_WORD];
  return (i + 2) <= length && nth(i + 1) == jit_dip_word;
}

bool quotation_jit::fast_2dip_p(cell i, cell length) {
  cell jit_2dip_word = parent->special_objects[JIT_2DIP_WORD];
  return (i + 2) <= length && nth(i + 1) == jit_2dip_word;
}

bool quotation_jit::fast_3dip_p(cell i, cell length) {
  cell jit_3dip_word = parent->special_objects[JIT_3DIP_WORD];
  return (i + 2) <= length && nth(i + 1) == jit_3dip_word;
}

bool quotation_jit::declare_p(cell i, cell length) {
  cell jit_declare_word = parent->special_objects[JIT_DECLARE_WORD];
  return (i + 2) <= length && nth(i + 1) == jit_declare_word;
}

bool quotation_jit::mega_lookup_p(cell i, cell length) {
  return (i + 4) <= length &&
      TAG(nth(i + 1)) == FIXNUM_TYPE &&
      TAG(nth(i + 2)) == ARRAY_TYPE &&
      nth(i + 3) == parent->special_objects[MEGA_LOOKUP_WORD];
}

// Subprimitives should be flagged with whether they require a stack frame.
// See #295.
bool quotation_jit::special_subprimitive_p(cell obj) {
  return obj == parent->special_objects[SIGNAL_HANDLER_WORD] ||
         obj == parent->special_objects[LEAF_SIGNAL_HANDLER_WORD] ||
         obj == parent->special_objects[UNWIND_NATIVE_FRAMES_WORD];
}

// All quotations wants a stack frame, except if they contain:
//   1) calls to the special subprimitives, see #295.
//   2) mega cache lookups, see #651
bool quotation_jit::stack_frame_p() {
  cell length = array_capacity(elements.untagged());
  for (cell i = 0; i < length; i++) {
    cell obj = nth(i);
    cell tag = TAG(obj);
    if ((tag == WORD_TYPE && special_subprimitive_p(obj)) ||
        (tag == ARRAY_TYPE && mega_lookup_p(i, length)))
      return false;
  }
  return true;
}

static bool trivial_quotation_p(array* elements) {
  return array_capacity(elements) == 1 &&
      TAG(array_nth(elements, 0)) == WORD_TYPE;
}

// Allocates memory (emit)
void quotation_jit::emit_epilog(bool needed) {
  if (needed) {
    emit(parent->special_objects[JIT_SAFEPOINT]);
    emit(parent->special_objects[JIT_EPILOG]);
  }
}

// Allocates memory conditionally
void quotation_jit::emit_quotation(cell quot_) {
  data_root<quotation> quot(quot_, parent);

  array* elements = untag<array>(quot->array);

  // If the quotation consists of a single word, compile a direct call
  // to the word.
  if (trivial_quotation_p(elements))
    literal(array_nth(elements, 0));
  else {
    if (compiling)
      parent->jit_compile_quotation(quot.value(), relocate);
    literal(quot.value());
  }
}

// Allocates memory (parameter(), literal(), emit_epilog, emit_with_literal)
void quotation_jit::iterate_quotation() {
  bool stack_frame = stack_frame_p();

  set_position(0);

  if (stack_frame) {
    emit(parent->special_objects[JIT_SAFEPOINT]);
    emit(parent->special_objects[JIT_PROLOG]);
  }

  cell length = array_capacity(elements.untagged());
  bool tail_call = false;

  for (cell i = 0; i < length; i++) {
    set_position(i);
    data_root<object> obj(nth(i), parent);

    switch (obj.type()) {
      case WORD_TYPE:
        // Sub-primitives
        if (to_boolean(obj.as<word>()->subprimitive)) {
          tail_call = emit_subprimitive(obj.value(),     // word
                                        i == length - 1, // tail_call_p
                                        stack_frame);    // stack_frame_p
        }                                                // Everything else
        else if (i == length - 1) {
          emit_epilog(stack_frame);
          tail_call = true;
          word_jump(obj.value());
        } else
          word_call(obj.value());
        break;
      case WRAPPER_TYPE:
        push(obj.as<wrapper>()->object);
        break;
      case BYTE_ARRAY_TYPE:
        // Primitive calls
        if (primitive_call_p(i, length)) {
// On x86-64 and PowerPC, the VM pointer is stored in a register;
// on other platforms, the RT_VM relocation is used and it needs
// an offset parameter
#ifdef FACTOR_X86
          parameter(tag_fixnum(0));
#endif
          parameter(obj.value());
          parameter(false_object);
#ifdef FACTOR_PPC_TOC
          parameter(obj.value());
          parameter(false_object);
#endif
          emit(parent->special_objects[JIT_PRIMITIVE]);

          i++;
        } else
          push(obj.value());
        break;
      case QUOTATION_TYPE:
        // 'if' preceded by two literal quotations (this is why if and ? are
        // mutually recursive in the library, but both still work)
        if (fast_if_p(i, length)) {
          emit_epilog(stack_frame);
          tail_call = true;
          emit_quotation(nth(i));
          emit_quotation(nth(i + 1));
          emit(parent->special_objects[JIT_IF]);
          i += 2;
        } // dip
        else if (fast_dip_p(i, length)) {
          emit_quotation(obj.value());
          emit(parent->special_objects[JIT_DIP]);
          i++;
        } // 2dip
        else if (fast_2dip_p(i, length)) {
          emit_quotation(obj.value());
          emit(parent->special_objects[JIT_2DIP]);
          i++;
        } // 3dip
        else if (fast_3dip_p(i, length)) {
          emit_quotation(obj.value());
          emit(parent->special_objects[JIT_3DIP]);
          i++;
        } else
          push(obj.value());
        break;
      case ARRAY_TYPE:
        // Method dispatch
        if (mega_lookup_p(i, length)) {
          tail_call = true;
          emit_mega_cache_lookup(nth(i), untag_fixnum(nth(i + 1)), nth(i + 2));
          i += 3;
        } // Non-optimizing compiler ignores declarations
        else if (declare_p(i, length))
          i++;
        else
          push(obj.value());
        break;
      default:
        push(obj.value());
        break;
    }
  }

  if (!tail_call) {
    set_position(length);
    emit_epilog(stack_frame);
    emit(parent->special_objects[JIT_RETURN]);
  }
}

cell quotation_jit::word_stack_frame_size(cell obj) {
  if (special_subprimitive_p(obj))
    return SIGNAL_HANDLER_STACK_FRAME_SIZE;
  return JIT_FRAME_SIZE;
}

// Allocates memory
void quotation_jit::emit_mega_cache_lookup(cell methods_, fixnum index,
                                           cell cache_) {
  data_root<array> methods(methods_, parent);
  data_root<array> cache(cache_, parent);

  // Load the object from the datastack.
  emit_with_literal(parent->special_objects[PIC_LOAD],
                    tag_fixnum(-index * sizeof(cell)));

  // Do a cache lookup.
  emit_with_literal(parent->special_objects[MEGA_LOOKUP], cache.value());

  // If we end up here, the cache missed.
  emit(parent->special_objects[JIT_PROLOG]);

  // Push index, method table and cache on the stack.
  push(methods.value());
  push(tag_fixnum(index));
  push(cache.value());
  word_call(parent->special_objects[MEGA_MISS_WORD]);

  // Now the new method has been stored into the cache, and its on
  // the stack.
  emit(parent->special_objects[JIT_EPILOG]);
  emit(parent->special_objects[JIT_EXECUTE]);
}

// Allocates memory
code_block* factor_vm::jit_compile_quotation(cell owner_, cell quot_,
                                             bool relocating) {
  data_root<object> owner(owner_, this);
  data_root<quotation> quot(quot_, this);

  quotation_jit compiler(owner.value(), true, relocating, this);
  compiler.init_quotation(quot.value());
  compiler.iterate_quotation();

  cell frame_size = compiler.word_stack_frame_size(owner_);

  code_block* compiled = compiler.to_code_block(CODE_BLOCK_UNOPTIMIZED,
                                                frame_size);
  if (relocating)
    initialize_code_block(compiled);

  return compiled;
}

// Allocates memory
void factor_vm::jit_compile_quotation(cell quot_, bool relocating) {
  data_root<quotation> quot(quot_, this);
  if (!quotation_compiled_p(quot.untagged())) {
    code_block* compiled =
        jit_compile_quotation(quot.value(), quot.value(), relocating);
    quot.untagged()->entry_point = compiled->entry_point();
  }
}

// Allocates memory
void factor_vm::primitive_jit_compile() {
  jit_compile_quotation(ctx->pop(), true);
}

cell factor_vm::lazy_jit_compile_entry_point() {
  return untag<word>(special_objects[LAZY_JIT_COMPILE_WORD])->entry_point;
}

// push a new quotation on the stack
// Allocates memory
void factor_vm::primitive_array_to_quotation() {
  quotation* quot = allot<quotation>(sizeof(quotation));

  quot->array = ctx->peek();
  quot->cached_effect = false_object;
  quot->cache_counter = false_object;
  quot->entry_point = lazy_jit_compile_entry_point();

  ctx->replace(tag<quotation>(quot));
}

// Allocates memory (from_unsigned_cell)
void factor_vm::primitive_quotation_code() {
  data_root<quotation> quot(ctx->pop(), this);

  ctx->push(from_unsigned_cell(quot->entry_point));
  ctx->push(from_unsigned_cell((cell)quot->code() + quot->code()->size()));
}

// Allocates memory
fixnum factor_vm::quot_code_offset_to_scan(cell quot_, cell offset) {
  data_root<quotation> quot(quot_, this);
  data_root<array> array(quot->array, this);

  quotation_jit compiler(quot.value(), false, false, this);
  compiler.init_quotation(quot.value());
  compiler.compute_position(offset);
  compiler.iterate_quotation();

  return compiler.get_position();
}

// Allocates memory
cell factor_vm::lazy_jit_compile(cell quot_) {
  data_root<quotation> quot(quot_, this);

  FACTOR_ASSERT(!quotation_compiled_p(quot.untagged()));

  code_block* compiled =
      jit_compile_quotation(quot.value(), quot.value(), true);
  quot.untagged()->entry_point = compiled->entry_point();

  return quot.value();
}

// Allocates memory
VM_C_API cell lazy_jit_compile(cell quot, factor_vm* parent) {
  return parent->lazy_jit_compile(quot);
}

bool factor_vm::quotation_compiled_p(quotation* quot) {
  return quot->entry_point != 0 &&
         quot->entry_point != lazy_jit_compile_entry_point();
}

void factor_vm::primitive_quotation_compiled_p() {
  quotation* quot = untag_check<quotation>(ctx->pop());
  ctx->push(tag_boolean(quotation_compiled_p(quot)));
}

}
<|endoftext|>


<commit_before>/*  LibMary - C++ library for high-performance network servers
    Copyright (C) 2011 Dmitry Shatrov

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <libmary/log.h>

#include <libmary/connection_receiver.h>

namespace M {

namespace {
LogGroup libMary_logGroup_msg ("msg", LogLevel::N);
}

Connection::InputFrontend const ConnectionReceiver::conn_input_frontend = {
    processInput,
    processError
};

void
ConnectionReceiver::doProcessInput ()
{
    logD (msg, _func_);

    for (;;) {
	assert (recv_buf_pos < recv_buf_len);
	Size const toread = recv_buf_len - recv_buf_pos;
	if (toread == 0) {
	    logW_ (_func, "recieve buffer is full");
	    return;
	}

	Size nread;
	AsyncIoResult io_res;
	{
	    io_res = conn->read (Memory (recv_buf + recv_buf_pos, toread), &nread);
	    logD (msg, _func, "read(): ", io_res);
	    switch (io_res) {
		case AsyncIoResult::Again: {
		    // TODO if (recv_buf_pos >= recv_buf_len) then error.
		    return;
		} break;
		case AsyncIoResult::Error: {
		    logD_ (_func, "read() failed: ", exc->toString());
		    if (!error_reported) {
			error_reported = true;
			if (frontend && frontend->processError)
			    frontend.call (frontend->processError, /*(*/ exc /*)*/);
		    }
		    return;
		} break;
		case AsyncIoResult::Eof: {
		    if (frontend && frontend->processEof)
			frontend.call (frontend->processEof);
		    return;
		} break;
		case AsyncIoResult::Normal:
		case AsyncIoResult::Normal_Again:
		case AsyncIoResult::Normal_Eof:
		  // No-op
		    break;
		default:
		    unreachable ();
	    }
	}
	assert (nread <= toread);
	recv_buf_pos += nread;

	logD (msg, _func, "nread: ", nread, ", recv_accepted_pos: ", recv_accepted_pos, ", recv_buf_pos: ", recv_buf_pos);

//	if (recv_buf_pos >= recv_needed_len)
	assert (recv_accepted_pos <= recv_buf_pos);
	Size const toprocess = recv_buf_pos - recv_accepted_pos;
	Size num_accepted;
	ProcessInputResult res;
	if (!frontend.call_ret<ProcessInputResult> (&res, frontend->processInput, /*(*/
		     Memory (recv_buf + recv_accepted_pos, toprocess),
		     &num_accepted /*)*/))
	{
	    num_accepted = 0;
	    // TODO In MomentVideo, this does nothing.
	    res = ProcessInputResult::Error;
	}
	assert (num_accepted <= toprocess);
	logD (msg, _func, res);
	switch (res) {
	    case ProcessInputResult::Normal:
		assert (num_accepted == toprocess);
		recv_buf_pos = 0;
		recv_accepted_pos = 0;
		break;
	    case ProcessInputResult::Error:
		logD_ (_func, "user's input handler failed");
		if (!error_reported) {
		    error_reported = true;
		    if (frontend && frontend->processError) {
			InternalException internal_exc (InternalException::FrontendError);
			frontend.call (frontend->processError, /*(*/ &internal_exc /*)*/);
		    }
		}
		return;
	    case ProcessInputResult::Again:
		recv_accepted_pos += num_accepted;
		if (recv_accepted_pos > 0) {
		    if (recv_buf_len - recv_accepted_pos <= (recv_buf_len >> 1)) {
			logD (msg, _func, "shifting receive buffer, toprocess: ", toprocess, ", num_accepted: ", num_accepted);
			memcpy (recv_buf, recv_buf + recv_accepted_pos, toprocess - num_accepted);
			recv_buf_pos = toprocess - num_accepted;
			recv_accepted_pos = 0;
		    }
		}
		// If the buffer is full and the frontend wants more data, then
		// we fail to serve the client. This should never happen with
		// properly written frontends.
		if (recv_buf_pos >= recv_buf_len) {
		    logE_ (_func, "Read buffer is full, frontend should have consumed some data. "
			   "recv_accepted_pos: ", recv_accepted_pos, ", "
			   "recv_buf_pos: ", recv_buf_pos, ", "
			   "recv_buf_len: ", recv_buf_len);
		    unreachable ();
		}
		break;
	    case ProcessInputResult::InputBlocked:
		recv_accepted_pos += num_accepted;
		// TODO block input
		return;
	    default:
		unreachable ();
	}

	if (io_res == AsyncIoResult::Normal_Again)
	    return;

	if (io_res == AsyncIoResult::Normal_Eof) {
	    if (frontend && frontend->processEof)
		frontend.call (frontend->processEof);
	    return;
	}
    } // for (;;)
}

void
ConnectionReceiver::processInput (void * const _self)
{
    ConnectionReceiver * const self = static_cast <ConnectionReceiver*> (_self);
    self->doProcessInput ();
}

void
ConnectionReceiver::processError (Exception * const exc_,
				  void      * const _self)
{
//    logD_ (_func_);
    ConnectionReceiver * const self = static_cast <ConnectionReceiver*> (_self);

    if (self->error_reported) {
	return;
    }
    self->error_reported = true;

    if (self->frontend && self->frontend->processError)
	self->frontend.call (self->frontend->processError, /*(*/ exc_ /*)*/);
}

// TODO Deprecated constructor.
ConnectionReceiver::ConnectionReceiver (Object     * const coderef_container,
					Connection * const mt_nonnull conn)
    : DependentCodeReferenced (coderef_container),
      conn (conn),
      recv_buf_len (1 << 16 /* 64 Kb */),
      recv_buf_pos (0),
      recv_accepted_pos (0),
      error_reported (false)
{
    recv_buf = new Byte [recv_buf_len];
    assert (recv_buf);

    conn->setInputFrontend (Cb<Connection::InputFrontend> (&conn_input_frontend, this, getCoderefContainer()));
}

ConnectionReceiver::ConnectionReceiver (Object * const coderef_container)
    : DependentCodeReferenced (coderef_container),
      recv_buf_len (1 << 16 /* 64 Kb */),
      recv_buf_pos (0),
      recv_accepted_pos (0),
      error_reported (false)
{
    recv_buf = new Byte [recv_buf_len];
    assert (recv_buf);
}

ConnectionReceiver::~ConnectionReceiver ()
{
    delete[] recv_buf;
}

}

<commit_msg>logs cleanup<commit_after>/*  LibMary - C++ library for high-performance network servers
    Copyright (C) 2011 Dmitry Shatrov

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <libmary/log.h>

#include <libmary/connection_receiver.h>

namespace M {

namespace {
LogGroup libMary_logGroup_msg ("msg", LogLevel::N);
}

Connection::InputFrontend const ConnectionReceiver::conn_input_frontend = {
    processInput,
    processError
};

void
ConnectionReceiver::doProcessInput ()
{
    logD (msg, _func_);

    for (;;) {
	assert (recv_buf_pos < recv_buf_len);
	Size const toread = recv_buf_len - recv_buf_pos;
	if (toread == 0) {
	    logW_ (_func, "recieve buffer is full");
	    return;
	}

	Size nread;
	AsyncIoResult io_res;
	{
	    io_res = conn->read (Memory (recv_buf + recv_buf_pos, toread), &nread);
	    logD (msg, _func, "read(): ", io_res);
	    switch (io_res) {
		case AsyncIoResult::Again: {
		    // TODO if (recv_buf_pos >= recv_buf_len) then error.
		    return;
		} break;
		case AsyncIoResult::Error: {
		    logD_ (_func, "read() failed: ", exc->toString());
		    if (!error_reported) {
			error_reported = true;
			if (frontend && frontend->processError)
			    frontend.call (frontend->processError, /*(*/ exc /*)*/);
		    }
		    return;
		} break;
		case AsyncIoResult::Eof: {
		    if (frontend && frontend->processEof)
			frontend.call (frontend->processEof);
		    return;
		} break;
		case AsyncIoResult::Normal:
		case AsyncIoResult::Normal_Again:
		case AsyncIoResult::Normal_Eof:
		  // No-op
		    break;
		default:
		    unreachable ();
	    }
	}
	assert (nread <= toread);
	recv_buf_pos += nread;

	logD (msg, _func, "nread: ", nread, ", recv_accepted_pos: ", recv_accepted_pos, ", recv_buf_pos: ", recv_buf_pos);

//	if (recv_buf_pos >= recv_needed_len)
	assert (recv_accepted_pos <= recv_buf_pos);
	Size const toprocess = recv_buf_pos - recv_accepted_pos;
	Size num_accepted;
	ProcessInputResult res;
	if (!frontend.call_ret<ProcessInputResult> (&res, frontend->processInput, /*(*/
		     Memory (recv_buf + recv_accepted_pos, toprocess),
		     &num_accepted /*)*/))
	{
	    num_accepted = 0;
	    // TODO In MomentVideo, this does nothing.
	    res = ProcessInputResult::Error;
	}
	assert (num_accepted <= toprocess);
	logD (msg, _func, res);
	switch (res) {
	    case ProcessInputResult::Normal:
		assert (num_accepted == toprocess);
		recv_buf_pos = 0;
		recv_accepted_pos = 0;
		break;
	    case ProcessInputResult::Error:
//		logD_ (_func, "user's input handler failed");
		if (!error_reported) {
		    error_reported = true;
		    if (frontend && frontend->processError) {
			InternalException internal_exc (InternalException::FrontendError);
			frontend.call (frontend->processError, /*(*/ &internal_exc /*)*/);
		    }
		}
		return;
	    case ProcessInputResult::Again:
		recv_accepted_pos += num_accepted;
		if (recv_accepted_pos > 0) {
		    if (recv_buf_len - recv_accepted_pos <= (recv_buf_len >> 1)) {
			logD (msg, _func, "shifting receive buffer, toprocess: ", toprocess, ", num_accepted: ", num_accepted);
			memcpy (recv_buf, recv_buf + recv_accepted_pos, toprocess - num_accepted);
			recv_buf_pos = toprocess - num_accepted;
			recv_accepted_pos = 0;
		    }
		}
		// If the buffer is full and the frontend wants more data, then
		// we fail to serve the client. This should never happen with
		// properly written frontends.
		if (recv_buf_pos >= recv_buf_len) {
		    logE_ (_func, "Read buffer is full, frontend should have consumed some data. "
			   "recv_accepted_pos: ", recv_accepted_pos, ", "
			   "recv_buf_pos: ", recv_buf_pos, ", "
			   "recv_buf_len: ", recv_buf_len);
		    unreachable ();
		}
		break;
	    case ProcessInputResult::InputBlocked:
		recv_accepted_pos += num_accepted;
		// TODO block input
		return;
	    default:
		unreachable ();
	}

	if (io_res == AsyncIoResult::Normal_Again)
	    return;

	if (io_res == AsyncIoResult::Normal_Eof) {
	    if (frontend && frontend->processEof)
		frontend.call (frontend->processEof);
	    return;
	}
    } // for (;;)
}

void
ConnectionReceiver::processInput (void * const _self)
{
    ConnectionReceiver * const self = static_cast <ConnectionReceiver*> (_self);
    self->doProcessInput ();
}

void
ConnectionReceiver::processError (Exception * const exc_,
				  void      * const _self)
{
//    logD_ (_func_);
    ConnectionReceiver * const self = static_cast <ConnectionReceiver*> (_self);

    if (self->error_reported) {
	return;
    }
    self->error_reported = true;

    if (self->frontend && self->frontend->processError)
	self->frontend.call (self->frontend->processError, /*(*/ exc_ /*)*/);
}

// TODO Deprecated constructor.
ConnectionReceiver::ConnectionReceiver (Object     * const coderef_container,
					Connection * const mt_nonnull conn)
    : DependentCodeReferenced (coderef_container),
      conn (conn),
      recv_buf_len (1 << 16 /* 64 Kb */),
      recv_buf_pos (0),
      recv_accepted_pos (0),
      error_reported (false)
{
    recv_buf = new Byte [recv_buf_len];
    assert (recv_buf);

    conn->setInputFrontend (Cb<Connection::InputFrontend> (&conn_input_frontend, this, getCoderefContainer()));
}

ConnectionReceiver::ConnectionReceiver (Object * const coderef_container)
    : DependentCodeReferenced (coderef_container),
      recv_buf_len (1 << 16 /* 64 Kb */),
      recv_buf_pos (0),
      recv_accepted_pos (0),
      error_reported (false)
{
    recv_buf = new Byte [recv_buf_len];
    assert (recv_buf);
}

ConnectionReceiver::~ConnectionReceiver ()
{
    delete[] recv_buf;
}

}

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/software/license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <iostream> // std::cerr
#include <algorithm> // std::transform
#include <fstream> // std::ifstream, std::ofstream
#include <string> // std::string
#include <vector> // std::vector
#include <sstream> // std::ostringstream

#include "GaussianDistribution.h"
#include "LatinHypercubeGenerator.h"
#include "Parameter.h"
#include "UniformDistribution.h"
#include "Paths.h"

#include "madaisys/SystemTools.hxx"

static const char usage[] =
  "usage:\n"
  "  generateTrainingPoints [options] <parameters file> <output directory> <number of points>\n"
  "\n"
  "<parameters file> is a file containing a list of parameters and their ranges\n"
  "\n"
  "  The file should be a text file with a separate line for each parameter\n"
  "  listing the name of the parameter, the type of prior distribution for the\n"
  "  parameter, and a list of parameters defining the prior distribution, e.g.\n"
  "\n"
  "  temperature uniform 245.2 288.0\n"
  "  pressure gaussian 4.7 2.1\n"
  "  ...\n"
  "\n"
  "  Two types of prior distributions are available, uniform and Gaussian.\n"
  "  - Uniform distributions take two numeric arguments, a minimum and maximum\n"
  "    value that define a range outside of which the likelihood is 0.\n"
  "\n"
  "    <parameter name> uniform <range min> <range max>\n"
  "\n"
  "  - Gaussian distributions take two numeric arguments, a mean and a\n"
  "    standard deviation.\n"
  "\n"
  "    <parameter name> gaussian <mean> <standard deviation>\n"
  "\n"
  "\n"
  "<output directory> is a path to the name of the directory that will be created\n"
  "   and which will contain the parameter files holding parameter values\n"
  "   generated by a latin hypercube sampling.\n"
  "\n"
  "\n"
  "<number of points> is the number of points to generate for training.\n"
  "\n"
  "\n"
  "Options:\n"
  "\n"
  "  -h,--help                          Display help message.\n"
  "\n"
  "  -v,--verbose                       Print extra information.\n"
  "\n"
  "  -f,--format {directories,emulator} Select the output format."
  "\n"
  "  -p,--percentile                    Partition space by parameter prior\n"
  "                                     distribution percentile.\n"
  "\n"
  "  -s,--stddev <value>                Number of standard deviations from\n"
  "                                     mean of a parameter's Gaussian\n"
  "                                     distributed prior to include in the\n"
  "                                     sampling.\n"
  "\n";

typedef enum {
  DIRECTORIES_FORMAT, // Pratt format
  EMULATOR_FORMAT     // GaussianProcessEmulator format
} FormatType;

struct CommandLineOptions {
  bool verbose;
  const char * parametersFile;  // First non-flag argument.
  const char * outputDirectory; // Second non-flag argument.
  FormatType formatType;        // Type of the output
  bool partitionSpaceByPercentile;
  double standardDeviations;
  int numberOfTrainingPoints;
};

std::string LowerCase( char * buffer )
{
  std::string outBuffer( buffer );

  std::transform( outBuffer.begin(), outBuffer.end(),
                  outBuffer.begin(), ::tolower );

  return outBuffer;
}

void LowerCase( std::string & s )
{
  std::transform( s.begin(), s.end(),
                  s.begin(), ::tolower );
}

bool ParseCommandLineOptions( int argc, char* argv[], struct CommandLineOptions & options)
{
  // Default values for command-line options
  options.verbose = false;
  options.parametersFile = NULL;
  options.outputDirectory = NULL;
  options.formatType = DIRECTORIES_FORMAT;
  options.partitionSpaceByPercentile = false;
  options.standardDeviations = 3.0;
  options.numberOfTrainingPoints = 100;

  // Parse options
  int argIndex;
  for ( argIndex = 1; argIndex < argc; ++argIndex ) {
    std::string argString( argv[ argIndex ] );

    if ( argString == "-v" || argString == "--verbose" ) {
      options.verbose = true;
    } else if ( argString == "-h" || argString == "--help" ) {
      std::cerr << usage;
      return false;
    } else if ( argString == "-f" || argString == "--format" ) {
      if ( argIndex + 1 < argc ) {
        std::string argString2 = LowerCase( argv[ argIndex + 1 ] );
        if ( argString2 == "directories" ) {
          options.formatType = DIRECTORIES_FORMAT;
        } else if ( argString2 == "emulator" ) {
          options.formatType = EMULATOR_FORMAT;
        } else {
          std::cerr << "Unknown format type '" << argString2 << "' provided to '"
                    << argString << "'. Expected 'directories' or 'emulator'.\n";
          return false;
        }
        argIndex++;
      } else {
        std::cerr << "No format type provided to argument '" << argString
                  << "'. Expected 'directories' or 'emulator'.\n";
        return false;
      }
    } else if ( argString == "-p" || argString == "--percentile" ) {
      options.partitionSpaceByPercentile = true;
    } else if ( argString == "-s" || argString == "--stddev" ) {
      if ( argIndex + 1 < argc ) {
        argIndex++;
        std::string argString2( argv[ argIndex ] );
        options.standardDeviations = atof( argString2.c_str() );
        if ( options.standardDeviations == 0.0 ) {
          std::cerr << "Standard deviations set to 0.0 is not valid. "
                    << "Did you supply a number to '" << argString
                    << "'?\n";
          return false;
        }
      } else {
        std::cerr << "Missing value for '" << argString << "'.\n";
        return false;
      }
    } else {
      break; // No switch
    }
  }

  if ( argIndex < argc ) {
    options.parametersFile = argv[ argIndex++ ];
  } else {
    std::cerr << usage;
    return false;
  }

  if ( argIndex < argc ) {
    options.outputDirectory = argv[ argIndex++ ];
  } else {
    std::cerr << usage;
    return false;
  }

  if ( argIndex < argc ) {
    options.numberOfTrainingPoints = atoi( argv[ argIndex++ ] );
    if ( options.numberOfTrainingPoints <= 0 ) {
      std::cerr << "Number of training points must be greater than 0.\n";
      return false;
    }
  } else {
    std::cerr << usage;
    return false;
  }

  if ( argIndex < argc ) {
    std::cerr << "Extra arguments after '" << options.outputDirectory << "'\n";
    return false;
  }

  // Everything went well
  return true;
}

static void discard_comments( std::istream & i, char comment_character ) {
  int c;
  while (i.good() && ((c = i.peek()) != EOF)) {
    if ((c == ' ') || (c == '\t') || ( c == '\n' )) {
      char ch;
      i.get(ch); // discard whitespace at beginning of line;
    } else if (c == comment_character) {
      std::string s;
      std::getline( i, s );
    } else {
      return; // line begins with some non-comment, non-whitespace character.
    }
  }
}

bool ReadParameters( const struct CommandLineOptions & options,
                     std::vector< madai::Parameter > & parameters )
{
  parameters.clear();

  std::ifstream parameterFile(options.parametersFile);
  if (! parameterFile.good()) {
    std::cerr << "[ReadParameters] Unable to open file " << options.parametersFile << ".";
    return false;
  }

  if ( options.verbose ) {
    std::cout << "Opened file '" << options.parametersFile << "'\n";
  }

  // Parse each parameter as it is listed on a line
  std::string parameterName;
  std::string distributionType;
  discard_comments(parameterFile, '#');
  while (parameterFile >> distributionType >> parameterName) {
    if (! parameterFile.good()) {
      parameterFile.close();
      break;
    }
    LowerCase(distributionType);
    if ( options.verbose ) {
      std::cout << "Read parameter '" << parameterName << "' "
                << "which is of type '" << distributionType << "' ";
    }

    madai::Distribution *distribution = NULL;
    madai::UniformDistribution uniform;
    madai::GaussianDistribution gaussian;

    if ( distributionType == "uniform" ) {
      // Parse minimum and maximum values
      double minimum, maximum;
      parameterFile >> minimum >> maximum;
      if (! parameterFile.good()) {
        std::cerr << "Could not read uniform distribution minimum and maximum\n";
        parameterFile.close();
        return false;
      }
      if ( options.verbose ) {
        std::cout << "with range [" << minimum << ", " << maximum << "]\n";
      }
      uniform.SetMinimum( minimum );
      uniform.SetMaximum( maximum );
      distribution = &uniform;

    } else if ( distributionType == "gaussian" ) {
      // Parse mean and standard deviation
      double mean, standardDeviation;
      parameterFile >> mean >> standardDeviation;
      if (! parameterFile.good()) {
        std::cerr << "Could not read Gaussian distribution mean and standard deviation\n";
        parameterFile.close();
        return false;
      }

      if ( options.verbose ) {
        std::cout << "with mean " << mean << " and standard deviation "
                  << standardDeviation << "\n";
      }

      gaussian.SetMean( mean );
      gaussian.SetStandardDeviation( standardDeviation );
      distribution = &gaussian;
    } else {
      std::cerr << "Unknown distribution type '" << distributionType << "'\n";
      parameterFile.close();
      return false;
    }
    parameters.push_back( madai::Parameter( parameterName, *distribution ) );
    discard_comments(parameterFile, '#');
  }

  parameterFile.close();
  // Everything went okay
  return true;
}

bool WriteDirectoriesFormat( const struct CommandLineOptions & options,
                             const std::vector< madai::Parameter > & parameters,
                             const std::vector< madai::Sample > & samples ) {
  // Create the directory structure
  bool directoryCreated = madaisys::SystemTools::MakeDirectory( options.outputDirectory );
  if ( !directoryCreated ) {
    std::cerr << "Could not create directory '" << options.outputDirectory
              << "'\n";
    return false;
  }

  std::string directory( options.outputDirectory );
  std::string experimental_results(
    directory + madai::Paths::SEPARATOR + madai::Paths::EXPERIMENTAL_RESULTS_DIRECTORY );
  std::string model_outputs(
    directory + madai::Paths::SEPARATOR + madai::Paths::MODEL_OUTPUT_DIRECTORY );
  std::string statistical_analysis(
    directory + madai::Paths::SEPARATOR + "statistical_analysis" );

  directoryCreated = directoryCreated &&
    madaisys::SystemTools::MakeDirectory( experimental_results.c_str() );
  directoryCreated = directoryCreated &&
    madaisys::SystemTools::MakeDirectory( model_outputs.c_str() );
  directoryCreated = directoryCreated &&
    madaisys::SystemTools::MakeDirectory( statistical_analysis.c_str() );

  // Now create the run directories
  for ( size_t i = 0; i < samples.size(); ++i ) {
    const madai::Sample & sample = samples[i];

    std::ostringstream buffer;
    buffer << model_outputs << "/run"
           << std::setw( 7 ) << std::setfill( '0' ) << i;
    std::string runDirectory(buffer.str());

    if ( options.verbose ) {
      std::cout << runDirectory << "\n";
    }

    directoryCreated = directoryCreated &&
      madaisys::SystemTools::MakeDirectory( runDirectory.c_str() );

    // Write the parameters to the parameters.dat file
    std::string parametersFile( runDirectory + "/parameters.dat" );
    std::ofstream outfile(parametersFile.c_str());
    if (! outfile) {
      std::cerr << "Could not open file '" << parametersFile << "'\n";
      return false;
    }

    assert( parameters.size() == sample.m_ParameterValues.size() );
    for ( size_t j = 0; j < parameters.size(); ++j ) {
      outfile << parameters[ j ].m_Name << ' '
              << sample.m_ParameterValues[ j ] << '\n';
    }

    outfile.close();
  }

  return true;
}

bool WriteEmulatorFormat( const struct CommandLineOptions & options,
                          const std::vector< madai::Parameter > & parameters,
                          const std::vector< madai::Sample > & samples ) {
  // Create the output directory
  bool directoryCreated = madaisys::SystemTools::MakeDirectory( options.outputDirectory );
  if ( !directoryCreated ) {
    std::cerr << "Could not create directory '" << options.outputDirectory
              << "'\n";
    return false;
  }

  // Open the output file
  std::string outputFile( options.outputDirectory );
  outputFile += "/emulator.dat";
  std::ofstream outfile(outputFile.c_str());
  if (! outfile) {
    std::cerr << "Could not create output file '" << outputFile << "'\n";
    return false;
  }

  // Print some comments
  outfile << "# created by generateTrainingPoints\n";

  // Print VERSION
  outfile << "VERSION 1\n";

  // Print the PARAMETERS
  outfile << "PARAMETERS\n";

  for ( size_t i = 0; i < parameters.size(); ++i ) {
    outfile << parameters[i].m_Name << ' ';
    const madai::Distribution * priorDistribution =
      parameters[i].GetPriorDistribution();
    const madai::UniformDistribution * uniformDistribution =
      dynamic_cast< const madai::UniformDistribution *>( priorDistribution );
    const madai::GaussianDistribution * gaussianDistribution =
      dynamic_cast< const madai::GaussianDistribution *>( priorDistribution );
    if ( uniformDistribution ) {
      outfile << "UNIFORM "
              << uniformDistribution->GetMinimum() << ' '
              << uniformDistribution->GetMaximum() << '\n';
    } else if ( gaussianDistribution ) {
      outfile << "GAUSSIAN "
              << gaussianDistribution->GetMean() << ' '
              << gaussianDistribution->GetStandardDeviation() << '\n';
    } else {
      std::cerr << "Unknown prior type\n";
      return false;
    }
  }

  // Print training points
  outfile << "NUMBER_OF_TRAINING_POINTS " << samples.size() << '\n';

  // Print parameter values at training points
  outfile << "PARAMETER_VALUES\n";

  for ( size_t i = 0; i < samples.size(); ++i ) {
    const madai::Sample & sample = samples[i];

    for ( size_t j = 0; j < sample.m_ParameterValues.size(); ++j ) {
      outfile << sample.m_ParameterValues[j] << ' ';
    }
    outfile << "\n";
  }
  outfile.close();

  return true;
}

int main( int argc, char * argv[] ) {
  struct CommandLineOptions options;
  if ( !ParseCommandLineOptions( argc, argv, options ) ) {
    return EXIT_FAILURE;
  }

  if ( options.verbose ) {
    std::cout << "Options: \n";
    std::cout << "  --verbose: " << options.verbose << "\n";
    std::cout << "  --format: ";
    if ( options.formatType == DIRECTORIES_FORMAT ) std::cout << "directories\n";
    if ( options.formatType == EMULATOR_FORMAT ) std::cout << "emulator\n";
    std::cout << "  --percentile: " << options.partitionSpaceByPercentile << "\n";
    std::cout << "  --stddev: " << options.standardDeviations << "\n";
    std::cout << "  <parameters file>: " << options.parametersFile << "\n";
    std::cout << "  <output directory>: " << options.outputDirectory << "\n";
    std::cout << "  <number of points>: " << options.numberOfTrainingPoints << "\n";
  }

  // Read in parameter priors
  std::vector< madai::Parameter > parameters;
  bool parametersRead = ReadParameters( options, parameters );
  if ( !parametersRead ) {
    std::cerr << "Could not read parameters from prior file '"
              << options.parametersFile << "'" << std::endl;
    return EXIT_FAILURE;
  }

  // Create the Latin hypercube sampling
  madai::LatinHypercubeGenerator sampleGenerator;
  sampleGenerator.SetStandardDeviations( options.standardDeviations );
  sampleGenerator.SetPartitionSpaceByPercentile( options.partitionSpaceByPercentile );

  std::vector< madai::Sample > samples =
    sampleGenerator.Generate( options.numberOfTrainingPoints, parameters );

  if ( options.formatType == DIRECTORIES_FORMAT ) {
    WriteDirectoriesFormat( options, parameters, samples );
  } else if ( options.formatType == EMULATOR_FORMAT ) {
    WriteEmulatorFormat( options, parameters, samples );
  } else {
    std::cerr << "Unknown output format type" << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
<commit_msg>Updated useage to new format<commit_after>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/software/license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <iostream> // std::cerr
#include <algorithm> // std::transform
#include <fstream> // std::ifstream, std::ofstream
#include <string> // std::string
#include <vector> // std::vector
#include <sstream> // std::ostringstream

#include "GaussianDistribution.h"
#include "LatinHypercubeGenerator.h"
#include "RuntimeParameterFileReader.h"
#include "ApplicationUtilities.h"
#include "Parameter.h"
#include "UniformDistribution.h"
#include "Paths.h"

#include "madaisys/SystemTools.hxx"

static const char useage[] =
  "Useage:\n"
  "  generateTrainingPoints StatisticsDirectory\n"
  "\n"
  "StatisticsDirectory is the directory in which all statistical data will\n"
  "be stored. Contains the paameter file stat_params.dat\n"
  "\n"
  "Format of and parameters which can be set in stat_params.dat:\n"
  "MODEL_OUTPUT_DIRECTORY <value>\n"
  "EXPERIMENTAL_RESULTS_DIRECTORY <value>\n"
  "NUMBER_TRAINING_POINTS <values>\n"
  "GENERATE_TRAINING_POINTS_VERBOSE <value>\n"
  "GENERATE_TRAINING_POINTS_PERCENTILE_PARTITION <value>\n"
  "GENERATE_TRAINING_POINTS_NUMBER_STDDEV <value>\n"
  "\n"
  "Default values (if not specified):\n"
  "MODEL_OUTPUT_DIRECTORY = model_output\n"
  "EXPERIMENTAL_RESULTS_DIRECTORY = experimental_results\n"
  "NUMBER_TRAINING_POINTS = 100\n"
  "GENERATE_TRAINING_POINTS_VERBOSE = false\n"
  "GENERATE_TRAINING_POINTS_PERCENTILE_PARTITION = false\n"
  "GENERATE_TRAINING_POINTS_NUMBER_STDDEV = 3\n"
  "\n"
  "This reads from StatisticsDirectory/parameter_priors.dat in order to\n"
  "use LHS to generate a series of parameter files on which to run a model.\n"
  "\n"
  "parameter_priors.dat entry formats:\n"
  "uniform name min max\n"
  "gaussian name mean std_dev\n"
  "\n"
  "Only uniform and gaussian distributions are available\n"
  "\n";

struct RuntimeOptions {
  bool verbose;
  bool partitionSpaceByPercentile;
  std::string ModelOutputDirectory;
  std::string ExperimentalResultsDirectory;
  double standardDeviations;
  int numberOfTrainingPoints;
};

std::string LowerCase( char * buffer )
{
  std::string outBuffer( buffer );

  std::transform( outBuffer.begin(), outBuffer.end(),
                  outBuffer.begin(), ::tolower );

  return outBuffer;
}

void LowerCase( std::string & s )
{
  std::transform( s.begin(), s.end(),
                  s.begin(), ::tolower );
}

bool ParseRuntimeOptions( int argc, char* argv[], struct RuntimeOptions & options)
{
  // Default values for command-line options
  options.verbose = false;
  options.ModelOutputDirectory = madai::Paths::MODEL_OUTPUT_DIRECTORY;
  options.ExperimentalResultsDirectory = madai::Paths::EXPERIMENTAL_RESULTS_DIRECTORY;
  options.partitionSpaceByPercentile = false;
  options.standardDeviations = 3.0;
  options.numberOfTrainingPoints = 100;

  // Parse options
  for ( unsigned int argIndex = 0; argIndex < argc; ++argIndex ) {
    std::string argString( argv[ argIndex ] );

    if ( argString == "GENERATE_TRAINING_POINTS_VERBOSE" ) {
      std::string tstring( argv[ argIndex + 1 ] );
      if ( tstring == "false" || tstring == "0" ) {
        options.verbose = false;
      } else if ( tstring == "true" || tstring == "1" ) {
        options.verbose = true;
      } else {
        std::cerr << "GENERATE_TRAINING_POINTS_VERBOSE given invalid argument \""
          << tstring << "\"\n";
        return false;
      }
      argIndex++;
    } else if ( argString == "GENERATE_TRAINING_POINTS_PERCENTILE_PARTITION" ) {
      std::string tstring( argv[ argIndex + 1 ] );
      if ( tstring == "false" || tstring == "0" ) {
        options.partitionSpaceByPercentile = false;
      } else if ( tstring == "true" || tstring == "1" ) {
        options.partitionSpaceByPercentile = true;
      } else {
        std::cerr << "GENERATE_TRAINING_POINTS_PERCENTILE_PARTITION given invalid argument \""
          << tstring << "\"\n";
        return false;
      }
      argIndex++;
    } else if ( argString == "GENERATE_TRAINING_POINTS_NUMBER_STDDEV" ) {
      std::string tstring( argv[ argIndex + 1 ] );
      options.standardDeviations = atof( tstring.c_str() );
      if ( options.standardDeviations <= 0.0 ) {
        std::cerr << "GENERATE_TRAINING_POINTS_NUMBER_STDDEV given invalid argument \""
          << tstring << "\"\n";
        return false;
      }
    } else if ( argString == "MODEL_OUTPUT_DIRECTORY" ) {
      options.ModelOutputDirectory = std::string( argv[ argIndex + 1 ] );
      argIndex++;
    } else if ( argString == "EXPERIMENTAL_RESULTS_DIRECTORY" ) {
      options.ExperimentalResultsDirectory = std::string( argv[ argIndex + 1 ] );
      argIndex++;
    } else if ( argString == "NUMBER_TRAINING_POINTS" ) {
      std::string tstring( argv[ argIndex + 1 ] );
      options.numberOfTrainingPoints = atoi( tstring.c_str() );
      if ( options.numberOfTrainingPoints <= 0 ) {
        std::cerr << "NUMBER_TRAINING_POINTS given invalid argument \""
          << tstring << "\"\n";
        return false;
      }
      argIndex++;
    }
  }

  // Everything went well
  return true;
}

static void discard_comments( std::istream & i, char comment_character ) {
  int c;
  while (i.good() && ((c = i.peek()) != EOF)) {
    if ((c == ' ') || (c == '\t') || ( c == '\n' )) {
      char ch;
      i.get(ch); // discard whitespace at beginning of line;
    } else if (c == comment_character) {
      std::string s;
      std::getline( i, s );
    } else {
      return; // line begins with some non-comment, non-whitespace character.
    }
  }
}

bool ReadParameters( std::string parametersFile,
                     std::vector< madai::Parameter > & parameters,
                     bool verbose )
{
  parameters.clear();

  std::ifstream parameterFile(parametersFile.c_str());
  if (! parameterFile.good()) {
    std::cerr << "[ReadParameters] Unable to open file " << parametersFile << ".";
    return false;
  }

  if ( verbose ) {
    std::cout << "Opened file '" << parametersFile << "'\n";
  }

  // Parse each parameter as it is listed on a line
  std::string parameterName;
  std::string distributionType;
  discard_comments(parameterFile, '#');
  while (parameterFile >> distributionType >> parameterName) {
    if (! parameterFile.good()) {
      parameterFile.close();
      break;
    }
    LowerCase(distributionType);
    if ( verbose ) {
      std::cout << "Read parameter '" << parameterName << "' "
                << "which is of type '" << distributionType << "' ";
    }

    madai::Distribution *distribution = NULL;
    madai::UniformDistribution uniform;
    madai::GaussianDistribution gaussian;

    if ( distributionType == "uniform" ) {
      // Parse minimum and maximum values
      double minimum, maximum;
      parameterFile >> minimum >> maximum;
      if (! parameterFile.good()) {
        std::cerr << "Could not read uniform distribution minimum and maximum\n";
        parameterFile.close();
        return false;
      }
      if ( verbose ) {
        std::cout << "with range [" << minimum << ", " << maximum << "]\n";
      }
      uniform.SetMinimum( minimum );
      uniform.SetMaximum( maximum );
      distribution = &uniform;

    } else if ( distributionType == "gaussian" ) {
      // Parse mean and standard deviation
      double mean, standardDeviation;
      parameterFile >> mean >> standardDeviation;
      if (! parameterFile.good()) {
        std::cerr << "Could not read Gaussian distribution mean and standard deviation\n";
        parameterFile.close();
        return false;
      }

      if ( verbose ) {
        std::cout << "with mean " << mean << " and standard deviation "
                  << standardDeviation << "\n";
      }

      gaussian.SetMean( mean );
      gaussian.SetStandardDeviation( standardDeviation );
      distribution = &gaussian;
    } else {
      std::cerr << "Unknown distribution type '" << distributionType << "'\n";
      parameterFile.close();
      return false;
    }
    parameters.push_back( madai::Parameter( parameterName, *distribution ) );
    discard_comments(parameterFile, '#');
  }

  parameterFile.close();
  // Everything went okay
  return true;
}

bool WriteDirectories( const std::string ModelOutputDirectory,
                       const std::string ExperimentalResultsDirectory,
                       const std::vector< madai::Parameter > & parameters,
                       const std::vector< madai::Sample > & samples,
                       const bool verbose ) {
  // Create the directory structure
  bool directoryCreated = madaisys::SystemTools::MakeDirectory( ModelOutputDirectory.c_str() );
  if ( !directoryCreated ) {
    std::cerr << "Could not create directory '" << ModelOutputDirectory << "'\n";
    return false;
  }

  directoryCreated = madaisys::SystemTools::MakeDirectory( ExperimentalResultsDirectory.c_str() );
  if ( !directoryCreated ) {
    std::cerr << "Could not create directory '" << ExperimentalResultsDirectory << "'\n";
    return false;
  }

  // Now create the run directories
  for ( size_t i = 0; i < samples.size(); ++i ) {
    const madai::Sample & sample = samples[i];

    std::ostringstream buffer;
    buffer << ModelOutputDirectory << "/run"
    << std::setw( 7 ) << std::setfill( '0' ) << i;
    std::string runDirectory(buffer.str());

    if ( verbose ) {
      std::cout << runDirectory << "\n";
    }

    directoryCreated = directoryCreated &&
      madaisys::SystemTools::MakeDirectory( runDirectory.c_str() );

    // Write the parameters to parameters.dat file
    std::string parametersFile( runDirectory + "/parameters.dat" );
    std::ofstream outfile( parametersFile.c_str() );
    if ( !outfile ) {
      std::cerr << "Could not open file '" << parametersFile << "'\n";
      return false;
    }

    assert( parameters.size() == sample.m_ParameterValues.size() );
    for ( size_t j = 0; j < parameters.size(); ++j ) {
      outfile << parameters[ j ].m_Name << ' '
              << sample.m_ParameterValues[ j ] << '\n';
    }

    outfile.close();
  }

  return true;
}

int main( int argc, char * argv[] ) {
  std::string StatisticsDirectory;
  std::string ModelOutputDirectory;
  std::string ExperimentalResultsDirectory;
  if ( argc > 1 ) {
    StatisticsDirectory = std::string( argv[1] );
    madai::EnsurePathSeparatorAtEnd( StatisticsDirectory );
  } else {
    std::cerr << useage << '\n';
    return EXIT_FAILURE;
  }
  madai::RuntimeParameterFileReader RPFR;
  RPFR.ParseFile( StatisticsDirectory +
                  madai::Paths::RUNTIME_PARAMETER_FILE );
  char** Args = RPFR.GetArguments();
  int NArgs = RPFR.GetNumberOfArguments();
  struct RuntimeOptions options;
  if ( !ParseRuntimeOptions( NArgs, Args, options ) ) {
    return EXIT_FAILURE;
  }

  ModelOutputDirectory = StatisticsDirectory + options.ModelOutputDirectory;
  ExperimentalResultsDirectory = StatisticsDirectory + options.ExperimentalResultsDirectory;
  if ( options.verbose ) {
    std::cout << "Options: \n";
    std::cout << "  VERBOSE: " << options.verbose << "\n";
    std::cout << "  PERCENTILE_PARTITION: " << options.partitionSpaceByPercentile << "\n";
    std::cout << "  STANDARD_DEVIATIONS: " << options.standardDeviations << "\n";
    std::cout << "  NUMBER_TRAINING_POINTS: " << options.numberOfTrainingPoints << "\n";
    std::cout << "  MODEL_OUTPUT_DIRECTORY: " << ModelOutputDirectory << "\n";
    std::cout << "  EXPERIMENTAL_RESULTS_DIRECTORY: " << ExperimentalResultsDirectory << "\n";
  }

  // Read in parameter priors
  std::vector< madai::Parameter > parameters;
  std::string parametersFile =  StatisticsDirectory +
    madai::Paths::PARAMETER_PRIORS_FILE;
  bool parametersRead = ReadParameters( parametersFile, parameters, options.verbose );
  if ( !parametersRead ) {
    std::cerr << "Could not read parameters from prior file '"
              << parametersFile << "'" << std::endl;
    return EXIT_FAILURE;
  }

  // Create the Latin hypercube sampling
  madai::LatinHypercubeGenerator sampleGenerator;
  sampleGenerator.SetStandardDeviations( options.standardDeviations );
  sampleGenerator.SetPartitionSpaceByPercentile( options.partitionSpaceByPercentile );

  std::vector< madai::Sample > samples =
    sampleGenerator.Generate( options.numberOfTrainingPoints, parameters );

  WriteDirectories( ModelOutputDirectory, ExperimentalResultsDirectory, parameters,
                    samples, options.verbose );

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsPageObjectViewObjectContact.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 06:23:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SD_SLIDESORTER_PAGE_OBJECT_VIEW_OBJECT_CONTACT_HXX
#define SD_SLIDESORTER_PAGE_OBJECT_VIEW_OBJECT_CONTACT_HXX

#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <vcl/bitmapex.hxx>
#include <vcl/image.hxx>
#include <sfx2/viewfrm.hxx>

#include <memory>

class SdrPage;

namespace sdr { namespace contact {
class DisplayInfo;
} }

namespace sd { namespace slidesorter { namespace model {
class PageDescriptor;
} } }

namespace sd { namespace slidesorter { namespace cache {
class PageCache;
} } }

namespace sd { namespace slidesorter { namespace view {

class PageNotificationObjectContact;
class SlideSorterView;

/** This object-view-contact of page objects maintains a preview bitmap for
    the page to speed up redraws of the same.  It does so by colaborating
    with a cache of bitmaps (see ../cache).

    This class started as a subclass of ::sdr::contact::VOCBitmapBuffer but
    the class specific code had to be copied and adapted.  Therefore, it is
    now derived directly from ::sdr::contact::ViewObjectContact.
*/
class PageObjectViewObjectContact
    : public ::sdr::contact::ViewObjectContact
{
public:
    /** Create a new view-object-contact object for the given contact
        objects of both model and view.
        @param pCache
            The caller should provide a pointer to a preview cache, if
            available.  If given then the cache is used to control when to
            create a preview and to store it.  If NULL is given then the
            preview is created every time when requested.
    */
    PageObjectViewObjectContact (
        ::sdr::contact::ObjectContact& rObjectContact,
        ::sdr::contact::ViewContact& rViewContact,
        cache::PageCache* pCache);
    virtual ~PageObjectViewObjectContact (void);

    virtual void PaintObject (::sdr::contact::DisplayInfo& rDisplayInfo);

    /** The object is about to be deleted.  Tell the cache that it has not
        to rendere a preview anymore and absolutely must not call back.
    */
    virtual void PrepareDelete (void);

    /** Return the page that is painted by this object.
    */
    const SdrPage* GetPage (void) const;

    /** This fallback method is called when no preview cache is available.
        It creates a preview for the page.
    */
    BitmapEx CreatePreview (::sdr::contact::DisplayInfo& rDisplayInfo);

    /** This paint method simply calls the more specialized paint methods
        that paint single aspects of the content.  If you want to add or
        remove an aspect then overload this method.
    */
    virtual void PaintContent (
        ::sdr::contact::DisplayInfo& rDisplayInfo);

    Rectangle GetModelBoundingBox (void) const;

    /** Return the page descriptor of the slide sorter model that is
        associated with the same page object as this contact object is.
    */
    model::PageDescriptor& GetPageDescriptor (void) const;

    /** Return the device independent part of the page border.  This border
        is returned in pixel coordinates.  Note that the device dependent
        parts--for the page number and the page title--have to be added.
        This is done by CalculatePageModelBorder().
    */
    static SvBorder GetPagePixelBorder (void);

    /** Return the border widths in the screen coordinate system of the
        border arround the page object.  The border contains frames for
        selection, focus, the page name and number, and the indicator for
        the page transition.
        @param pDevice
            The output device is used to convert pixel coordinates into
            model coordinates.  When NULL is given then the device dependent
            part is not re-calculated but taken from an earlier calculation
            or from the default values.
        @param nPageCount
            The total number of pages is used to determine the width of the
            box that contains the page number.
    */
    static SvBorder CalculatePageModelBorder (
        OutputDevice* pDevice,
        int nPageCount);

    /** Calculate the size of the page number area so that all page numbers
        including the given number fit in.  Because this is device dependent
        we need the device as parameter.  The result is returned and stored
        in maPageNumberAreaPixelSize so that it can be used later without
        access to the device or page count.
    */
    static Size CalculatePageNumberAreaModelSize (
        OutputDevice* pDevice,
        int nPageCount);

    /** Return the bounding box of where the fade effect indicator is
        painted (when it is painted).
    */
    Rectangle GetFadeEffectIndicatorArea (OutputDevice* pDevice) const;

    /** Paint all parts of the frame arround a preview.  These are the
        border, the selection frame, the focus rectangle, and the mouse over
        effect.
        @param rDevice
            The output device to paint on.
        @param bShowMouseOverEffect
            This flag specifies whether to paint the mouse over effect or not.
    */
    void PaintFrame (
        OutputDevice& rDevice,
        bool bShowMouseOverEffect = false) const;

    /** Return the rectangle of the whole page object, the preview toghether
        with frames, indicators, and title, in pixel coordinates.
    */
    Rectangle GetPixelBox (const OutputDevice& rDevice);

    /** Return the rectangle of the preview in pixel coordinates.
    */
    Rectangle GetPreviewPixelBox (const OutputDevice& rDevice);

private:
    /// Gap between border of page object and inside of selection rectangle.
    static const sal_Int32 mnSelectionIndicatorOffset;
    /// Thickness of the selection rectangle.
    static const sal_Int32 mnSelectionIndicatorThickness;
    /// Gap between border of page object and inside of focus rectangle.
    static const sal_Int32 mnFocusIndicatorOffset;
    /// Size of width and height of the fade effect indicator in pixels.
    static const sal_Int32 mnFadeEffectIndicatorSize;
    static const sal_Int32 mnFadeEffectIndicatorOffset;
    /// Gap between border of page object and number rectangle.
    static const sal_Int32 mnPageNumberOffset;
    /// Offset and thickness of the mouse over effect rectangle.
    static const sal_Int32 mnMouseOverEffectOffset;
    static const sal_Int32 mnMouseOverEffectThickness;

    /** This flag is set to <FALSE/> when PrepareDelete() is called to
        indicate that further calls made to it must not call outside.
    */
    bool mbIsValid;

    cache::PageCache* mpCache;

    ::std::auto_ptr<PageNotificationObjectContact> mpNotifier;

    BitmapEx GetPreview (
        ::sdr::contact::DisplayInfo& rDisplayInfo,
        const Rectangle& rNewSizePixel);

    virtual void ActionChanged (void);

    /** Return the bounding box of where the page number is painted (when it
        is painted).
    */
    Rectangle GetPageNumberArea (OutputDevice* pDevice);

    /** Paint the preview bitmap.
    */
    void PaintPreview (::sdr::contact::DisplayInfo& rDisplayInfo);

    /** Paint a border arround the page preview.
    */
    void PaintBorder (OutputDevice& rDevice) const;

    /** Paint the focus indicator for the specified page.
    */
    void PaintFocusIndicator (
        OutputDevice& rDevice,
        bool bEraseBackground) const;

    /** Paint the selection indicator when the page is currently selected.
        Otherwise the call is ignored.
    */
    void PaintSelectionIndicator (OutputDevice& rDevice) const;

    /** Paint a mouse over effect.
        @param bVisible
            When bVisible is <FALSE/> then paint the area of the mouse over
            effect in the background color, i.e. erase it.
    */
    void PaintMouseOverEffect (OutputDevice& rDevice, bool bVisible) const;

    /** Paint the fade effect indicator which indicates whether a fade
        effect is currently associated with a page.
        @param rDescriptor
            The descriptor of the page for which to paint the fade effect
            indicator.
        @param bHighlight
            This flag specifies whether to paint the indicator highlighted
            (i.e. to indicate a mouse over effect) or the normal way.
    */
    void PaintFadeEffectIndicator (
        ::sdr::contact::DisplayInfo& rDisplayInfo,
        bool bHighlight = false) const;

    /** Paint the name of the page to the bottom right of the page object.
    */
    void PaintPageName (
        ::sdr::contact::DisplayInfo& rDisplayInfo) const;

    /** Paint the number of the page to the upper left of the page object.
    */
    void PaintPageNumber (
        ::sdr::contact::DisplayInfo& rDisplayInfo);
};

} } } // end of namespace ::sd::slidesorter::view

#endif
<commit_msg>INTEGRATION: CWS impress69 (1.8.76); FILE MERGED 2005/10/14 11:13:29 af 1.8.76.3: RESYNC: (1.8-1.9); FILE MERGED 2005/09/22 08:09:49 af 1.8.76.2: #i54916# Support for bitmap compression. 2005/09/14 11:34:46 af 1.8.76.1: #i54589# Added support for persistent caches.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsPageObjectViewObjectContact.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2005-10-24 07:44:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SD_SLIDESORTER_PAGE_OBJECT_VIEW_OBJECT_CONTACT_HXX
#define SD_SLIDESORTER_PAGE_OBJECT_VIEW_OBJECT_CONTACT_HXX

#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <vcl/bitmapex.hxx>
#include <vcl/image.hxx>
#include <sfx2/viewfrm.hxx>

#include <memory>
#include <boost/shared_ptr.hpp>

class SdrPage;

namespace sdr { namespace contact {
class DisplayInfo;
} }

namespace sd { namespace slidesorter { namespace model {
class PageDescriptor;
} } }

namespace sd { namespace slidesorter { namespace cache {
class PageCache;
} } }

namespace sd { namespace slidesorter { namespace view {

class PageNotificationObjectContact;
class SlideSorterView;

/** This object-view-contact of page objects maintains a preview bitmap for
    the page to speed up redraws of the same.  It does so by colaborating
    with a cache of bitmaps (see ../cache).

    This class started as a subclass of ::sdr::contact::VOCBitmapBuffer but
    the class specific code had to be copied and adapted.  Therefore, it is
    now derived directly from ::sdr::contact::ViewObjectContact.
*/
class PageObjectViewObjectContact
    : public ::sdr::contact::ViewObjectContact
{
public:
    /** Create a new view-object-contact object for the given contact
        objects of both model and view.
        @param pCache
            The caller should provide a pointer to a preview cache, if
            available.  If given then the cache is used to control when to
            create a preview and to store it.  If NULL is given then the
            preview is created every time when requested.
    */
    PageObjectViewObjectContact (
        ::sdr::contact::ObjectContact& rObjectContact,
        ::sdr::contact::ViewContact& rViewContact,
        const ::boost::shared_ptr<cache::PageCache>& rpCache);
    virtual ~PageObjectViewObjectContact (void);

    /** This method is primarily for releasing the current preview cache (by
        providing a NULL pointer.)
    */
    void SetCache (const ::boost::shared_ptr<cache::PageCache>& rpCache);

    virtual void PaintObject (::sdr::contact::DisplayInfo& rDisplayInfo);

    /** The object is about to be deleted.  Tell the cache that it has not
        to rendere a preview anymore and absolutely must not call back.
    */
    virtual void PrepareDelete (void);

    /** Return the page that is painted by this object.
    */
    const SdrPage* GetPage (void) const;

    /** This fallback method is called when no preview cache is available.
        It creates a preview for the page.
    */
    BitmapEx CreatePreview (::sdr::contact::DisplayInfo& rDisplayInfo);

    /** This paint method simply calls the more specialized paint methods
        that paint single aspects of the content.  If you want to add or
        remove an aspect then overload this method.
    */
    virtual void PaintContent (
        ::sdr::contact::DisplayInfo& rDisplayInfo);

    Rectangle GetModelBoundingBox (void) const;

    /** Return the page descriptor of the slide sorter model that is
        associated with the same page object as this contact object is.
    */
    model::PageDescriptor& GetPageDescriptor (void) const;

    /** Return the device independent part of the page border.  This border
        is returned in pixel coordinates.  Note that the device dependent
        parts--for the page number and the page title--have to be added.
        This is done by CalculatePageModelBorder().
    */
    static SvBorder GetPagePixelBorder (void);

    /** Return the border widths in the screen coordinate system of the
        border arround the page object.  The border contains frames for
        selection, focus, the page name and number, and the indicator for
        the page transition.
        @param pDevice
            The output device is used to convert pixel coordinates into
            model coordinates.  When NULL is given then the device dependent
            part is not re-calculated but taken from an earlier calculation
            or from the default values.
        @param nPageCount
            The total number of pages is used to determine the width of the
            box that contains the page number.
    */
    static SvBorder CalculatePageModelBorder (
        OutputDevice* pDevice,
        int nPageCount);

    /** Calculate the size of the page number area so that all page numbers
        including the given number fit in.  Because this is device dependent
        we need the device as parameter.  The result is returned and stored
        in maPageNumberAreaPixelSize so that it can be used later without
        access to the device or page count.
    */
    static Size CalculatePageNumberAreaModelSize (
        OutputDevice* pDevice,
        int nPageCount);

    /** Return the bounding box of where the fade effect indicator is
        painted (when it is painted).
    */
    Rectangle GetFadeEffectIndicatorArea (OutputDevice* pDevice) const;

    /** Paint all parts of the frame arround a preview.  These are the
        border, the selection frame, the focus rectangle, and the mouse over
        effect.
        @param rDevice
            The output device to paint on.
        @param bShowMouseOverEffect
            This flag specifies whether to paint the mouse over effect or not.
    */
    void PaintFrame (
        OutputDevice& rDevice,
        bool bShowMouseOverEffect = false) const;

    /** Return the rectangle of the whole page object, the preview toghether
        with frames, indicators, and title, in pixel coordinates.
    */
    Rectangle GetPixelBox (const OutputDevice& rDevice) const;

    /** Return the rectangle of the preview in pixel coordinates.
    */
    Rectangle GetPreviewPixelBox (const OutputDevice& rDevice) const;

private:
    /// Gap between border of page object and inside of selection rectangle.
    static const sal_Int32 mnSelectionIndicatorOffset;
    /// Thickness of the selection rectangle.
    static const sal_Int32 mnSelectionIndicatorThickness;
    /// Gap between border of page object and inside of focus rectangle.
    static const sal_Int32 mnFocusIndicatorOffset;
    /// Size of width and height of the fade effect indicator in pixels.
    static const sal_Int32 mnFadeEffectIndicatorSize;
    static const sal_Int32 mnFadeEffectIndicatorOffset;
    /// Gap between border of page object and number rectangle.
    static const sal_Int32 mnPageNumberOffset;
    /// Offset and thickness of the mouse over effect rectangle.
    static const sal_Int32 mnMouseOverEffectOffset;
    static const sal_Int32 mnMouseOverEffectThickness;

    /** This flag is set to <FALSE/> when PrepareDelete() is called to
        indicate that further calls made to it must not call outside.
    */
    bool mbIsValid;

    ::boost::shared_ptr<cache::PageCache> mpCache;

    ::std::auto_ptr<PageNotificationObjectContact> mpNotifier;

    bool mbInPrepareDelete;

    BitmapEx GetPreview (
        ::sdr::contact::DisplayInfo& rDisplayInfo,
        const Rectangle& rNewSizePixel);

    virtual void ActionChanged (void);

    /** Return the bounding box of where the page number is painted (when it
        is painted).
    */
    Rectangle GetPageNumberArea (OutputDevice* pDevice);

    /** Paint the preview bitmap.
    */
    void PaintPreview (::sdr::contact::DisplayInfo& rDisplayInfo);

    /** Paint a border arround the page preview.
    */
    void PaintBorder (OutputDevice& rDevice) const;

    /** Paint the focus indicator for the specified page.
    */
    void PaintFocusIndicator (
        OutputDevice& rDevice,
        bool bEraseBackground) const;

    /** Paint the selection indicator when the page is currently selected.
        Otherwise the call is ignored.
    */
    void PaintSelectionIndicator (OutputDevice& rDevice) const;

    /** Paint a mouse over effect.
        @param bVisible
            When bVisible is <FALSE/> then paint the area of the mouse over
            effect in the background color, i.e. erase it.
    */
    void PaintMouseOverEffect (OutputDevice& rDevice, bool bVisible) const;

    /** Paint the fade effect indicator which indicates whether a fade
        effect is currently associated with a page.
        @param rDescriptor
            The descriptor of the page for which to paint the fade effect
            indicator.
        @param bHighlight
            This flag specifies whether to paint the indicator highlighted
            (i.e. to indicate a mouse over effect) or the normal way.
    */
    void PaintFadeEffectIndicator (
        ::sdr::contact::DisplayInfo& rDisplayInfo,
        bool bHighlight = false) const;

    /** Paint the name of the page to the bottom right of the page object.
    */
    void PaintPageName (
        ::sdr::contact::DisplayInfo& rDisplayInfo) const;

    /** Paint the number of the page to the upper left of the page object.
    */
    void PaintPageNumber (
        ::sdr::contact::DisplayInfo& rDisplayInfo);
};

} } } // end of namespace ::sd::slidesorter::view

#endif
<|endoftext|>