<commit_before>#include "haxor/common/haxor.hh"
#include "haxor/common/cmd.hh"
#include "haxor/hvm/vm.hh"
#include "haxor/hvm/cpu.hh"

#include <iostream>

namespace haxor {
  timer::timer(const word_t step, const word_t int_no) : step(step), int_no(int_no) {
    enable();
    schedule();
  }

  void timer::enable() {
    enabled = true;
  }

  void timer::disable() {
    enabled = false;
  }

  void timer::schedule() {
    remaining_ticks = step;
  }

  void timer::tick() {
    if (remaining_ticks > 0) {
      remaining_ticks--;
    }
  }

  bool timer::check() {
    if (remaining_ticks == 0) {
      schedule();
      return enabled; //
    } else {
      return false;
    }
  }

  word_t timer::get_int_no() {
    return int_no;
  }

  cpu::cpu(class vm &vm) : vm(vm) {
  }

  void cpu::start_sys_timer() {
    sys_timer = std::thread([this] { sys_timer_loop(); });
  }

  void cpu::stop_sys_timer() {
    sys_timer_kill = true;
    sys_timer.join();
  }

  void cpu::sys_timer_loop() {
    while (!sys_timer_kill) {
      std::this_thread::sleep_for(std::chrono::milliseconds(system_timer_period));
      for (auto &item : timers) {
        item.tick();
      }
    }
  }

  std::vector<timer> &cpu::get_timers() {
    return timers;
  }

  void cpu::cycle() {
    try {
      if (!vm.get_mem().get_page(ip).get_attrs().exec) {
        throw segfault_error();
      }

      decode_opcode(vm.get_mem().read_word(ip), opcode);
      ip += sizeof(word_t);

      execute(opcode);

      for (auto &item : timers) {
        if (item.check()) {
          perform_int(item.get_int_no());
        }
      }
    } catch (const cpu_error &e) {
      raise_error(e.code);
    }
  }

  void cpu::execute(const opcode_t &op) {
    uint64_t tmp;

    switch(op.cmd) {
    case cmd_nop:
      break;

    case cmd_syscall:
      vm.get_os().syscall();
      break;

    case cmd_add:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) + regs.read(op.reg3));
      break;

    case cmd_addi:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) + op.imm);
      break;

    case cmd_sub:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) - regs.read(op.reg3));
      break;

    case cmd_mult:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) * regs.read(op.reg3));
      break;

    case cmd_div:
      validate_reg_write(op.reg1);
      if (regs.read(op.reg3) == 0) {
        throw div_by_zero_error();
      }
      regs.write(op.reg1, regs.read(op.reg2) / regs.read(op.reg3));
      break;

    case cmd_mod:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) % regs.read(op.reg3));
      break;

    case cmd_lw:
      validate_reg_write(op.reg1);
      tmp = regs.read(op.reg2) + op.imm;
      if (!vm.get_mem().get_page(tmp).get_attrs().read) {
        throw segfault_error();
      }
      regs.write(op.reg1, vm.get_mem().read_word(tmp));
      break;

    case cmd_sw:
      tmp = regs.read(op.reg1) + op.imm;
      if (!vm.get_mem().get_page(tmp).get_attrs().write) {
        throw segfault_error();
      }
      vm.get_mem().write_word(tmp, regs.read(op.reg2));

      break;

    case cmd_lui:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, op.imm << 32);
      break;

    case cmd_and:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) & regs.read(op.reg3));
      break;

    case cmd_andi:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) & op.imm);
      break;

    case cmd_or:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) | regs.read(op.reg3));
      break;

    case cmd_ori:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) | op.imm);
      break;

    case cmd_xor:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) ^ regs.read(op.reg3));
      break;

    case cmd_nor:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, ~(regs.read(op.reg2) | regs.read(op.reg3)));
      break;

    case cmd_slt:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) < regs.read(op.reg3) ? 1 : 0);
      break;

    case cmd_slti:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) < op.imm ? 1 : 0);
      break;

    case cmd_slli:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) << op.imm);
      break;

    case cmd_srli:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) >> op.imm);
      break;

    case cmd_sll:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) << regs.read(op.reg3));
      break;

    case cmd_srl:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) >> regs.read(op.reg3));
      break;

    case cmd_beq:
      if (regs.read(op.reg1) == regs.read(op.reg2)) {
        branch(op.imm);
      }
      break;

    case cmd_beql:
      if (regs.read(op.reg1) == regs.read(op.reg2)) {
        link();
        branch(op.imm);
      }
      break;

    case cmd_bne:
      if (regs.read(op.reg1) != regs.read(op.reg2)) {
        branch(op.imm);
      }
      break;

    case cmd_bnel:
      if (regs.read(op.reg1) != regs.read(op.reg2)) {
        link();
        branch(op.imm);
      }
      break;

    case cmd_j:
      jump(op.imm);
      break;

    case cmd_jr:
      ip = regs.read(op.reg1);
      break;

    case cmd_jal:
      link();
      jump(op.imm);
      break;

    case cmd_jalr:
      link();
      ip = regs.read(op.reg1);
      break;

    case cmd_int:
      perform_int(regs.read(op.reg1));
      break;

    case cmd_reti:
      // pop $ra
      regs.write(reg_return, vm.get_mem().read_word(regs.read(reg_stack)));
      regs.add(reg_stack, sizeof(word_t));

      // pop ip
      set_ip(vm.get_mem().read_word(regs.read(reg_stack)));
      regs.add(reg_stack, sizeof(word_t));
      break;

    default:
      throw broken_opcode_error();
    }
  }

  void cpu::set_ip(const uint64_t ip) {
    this->ip = ip;
  }

  regs& cpu::get_regs() {
    return regs;
  }

  void cpu::link() {
    regs.write(reg_return, ip);
  }

  void cpu::branch(const uint64_t target) {
    ip += target * sizeof(word_t);
  }

  void cpu::jump(const uint64_t target) {
    ip = target * sizeof(word_t);
  }

  void cpu::validate_reg_write(const uint8_t reg) {
    //
  }

  void cpu::perform_int(const word_t int_no) {
    if (int_no < 0 || int_no >= ivt_num) {
        throw std::invalid_argument("Invalid INT number.");
      }

      // push ip
      regs.add(reg_stack, -sizeof(word_t));
      vm.get_mem().write_word(regs.read(reg_stack), ip);

      // push $ra
      regs.add(reg_stack, -sizeof(word_t));
      vm.get_mem().write_word(regs.read(reg_stack), regs.read(reg_return));

      set_ip(vm.get_mem().read_word(int_no * sizeof(word_t)));
  }

  void cpu::raise_error(const word_t error_code) {
    perform_int(error_code);
  }
}
<commit_msg>inform about lack of isr<commit_after>#include "haxor/common/haxor.hh"
#include "haxor/common/cmd.hh"
#include "haxor/hvm/vm.hh"
#include "haxor/hvm/cpu.hh"

#include <iostream>

namespace haxor {
  timer::timer(const word_t step, const word_t int_no) : step(step), int_no(int_no) {
    enable();
    schedule();
  }

  void timer::enable() {
    enabled = true;
  }

  void timer::disable() {
    enabled = false;
  }

  void timer::schedule() {
    remaining_ticks = step;
  }

  void timer::tick() {
    if (remaining_ticks > 0) {
      remaining_ticks--;
    }
  }

  bool timer::check() {
    if (remaining_ticks == 0) {
      schedule();
      return enabled; //
    } else {
      return false;
    }
  }

  word_t timer::get_int_no() {
    return int_no;
  }

  cpu::cpu(class vm &vm) : vm(vm) {
  }

  void cpu::start_sys_timer() {
    sys_timer = std::thread([this] { sys_timer_loop(); });
  }

  void cpu::stop_sys_timer() {
    sys_timer_kill = true;
    sys_timer.join();
  }

  void cpu::sys_timer_loop() {
    while (!sys_timer_kill) {
      std::this_thread::sleep_for(std::chrono::milliseconds(system_timer_period));
      for (auto &item : timers) {
        item.tick();
      }
    }
  }

  std::vector<timer> &cpu::get_timers() {
    return timers;
  }

  void cpu::cycle() {
    try {
      if (!vm.get_mem().get_page(ip).get_attrs().exec) {
        throw segfault_error();
      }

      decode_opcode(vm.get_mem().read_word(ip), opcode);
      ip += sizeof(word_t);

      execute(opcode);

      for (auto &item : timers) {
        if (item.check()) {
          perform_int(item.get_int_no());
        }
      }
    } catch (const cpu_error &e) {
      raise_error(e.code);
    }
  }

  void cpu::execute(const opcode_t &op) {
    uint64_t tmp;

    switch(op.cmd) {
    case cmd_nop:
      break;

    case cmd_syscall:
      vm.get_os().syscall();
      break;

    case cmd_add:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) + regs.read(op.reg3));
      break;

    case cmd_addi:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) + op.imm);
      break;

    case cmd_sub:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) - regs.read(op.reg3));
      break;

    case cmd_mult:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) * regs.read(op.reg3));
      break;

    case cmd_div:
      validate_reg_write(op.reg1);
      if (regs.read(op.reg3) == 0) {
        throw div_by_zero_error();
      }
      regs.write(op.reg1, regs.read(op.reg2) / regs.read(op.reg3));
      break;

    case cmd_mod:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) % regs.read(op.reg3));
      break;

    case cmd_lw:
      validate_reg_write(op.reg1);
      tmp = regs.read(op.reg2) + op.imm;
      if (!vm.get_mem().get_page(tmp).get_attrs().read) {
        throw segfault_error();
      }
      regs.write(op.reg1, vm.get_mem().read_word(tmp));
      break;

    case cmd_sw:
      tmp = regs.read(op.reg1) + op.imm;
      if (!vm.get_mem().get_page(tmp).get_attrs().write) {
        throw segfault_error();
      }
      vm.get_mem().write_word(tmp, regs.read(op.reg2));

      break;

    case cmd_lui:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, op.imm << 32);
      break;

    case cmd_and:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) & regs.read(op.reg3));
      break;

    case cmd_andi:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) & op.imm);
      break;

    case cmd_or:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) | regs.read(op.reg3));
      break;

    case cmd_ori:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) | op.imm);
      break;

    case cmd_xor:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) ^ regs.read(op.reg3));
      break;

    case cmd_nor:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, ~(regs.read(op.reg2) | regs.read(op.reg3)));
      break;

    case cmd_slt:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) < regs.read(op.reg3) ? 1 : 0);
      break;

    case cmd_slti:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) < op.imm ? 1 : 0);
      break;

    case cmd_slli:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) << op.imm);
      break;

    case cmd_srli:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) >> op.imm);
      break;

    case cmd_sll:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) << regs.read(op.reg3));
      break;

    case cmd_srl:
      validate_reg_write(op.reg1);
      regs.write(op.reg1, regs.read(op.reg2) >> regs.read(op.reg3));
      break;

    case cmd_beq:
      if (regs.read(op.reg1) == regs.read(op.reg2)) {
        branch(op.imm);
      }
      break;

    case cmd_beql:
      if (regs.read(op.reg1) == regs.read(op.reg2)) {
        link();
        branch(op.imm);
      }
      break;

    case cmd_bne:
      if (regs.read(op.reg1) != regs.read(op.reg2)) {
        branch(op.imm);
      }
      break;

    case cmd_bnel:
      if (regs.read(op.reg1) != regs.read(op.reg2)) {
        link();
        branch(op.imm);
      }
      break;

    case cmd_j:
      jump(op.imm);
      break;

    case cmd_jr:
      ip = regs.read(op.reg1);
      break;

    case cmd_jal:
      link();
      jump(op.imm);
      break;

    case cmd_jalr:
      link();
      ip = regs.read(op.reg1);
      break;

    case cmd_int:
      perform_int(regs.read(op.reg1));
      break;

    case cmd_reti:
      // pop $ra
      regs.write(reg_return, vm.get_mem().read_word(regs.read(reg_stack)));
      regs.add(reg_stack, sizeof(word_t));

      // pop ip
      set_ip(vm.get_mem().read_word(regs.read(reg_stack)));
      regs.add(reg_stack, sizeof(word_t));
      break;

    default:
      throw broken_opcode_error();
    }
  }

  void cpu::set_ip(const uint64_t ip) {
    this->ip = ip;
  }

  regs& cpu::get_regs() {
    return regs;
  }

  void cpu::link() {
    regs.write(reg_return, ip);
  }

  void cpu::branch(const uint64_t target) {
    ip += target * sizeof(word_t);
  }

  void cpu::jump(const uint64_t target) {
    ip = target * sizeof(word_t);
  }

  void cpu::validate_reg_write(const uint8_t reg) {
    //
  }

  void cpu::perform_int(const word_t int_no) {
    if (int_no < 0 || int_no >= ivt_num) {
        throw std::invalid_argument("Invalid INT number.");
      }

      // push ip
      regs.add(reg_stack, -sizeof(word_t));
      vm.get_mem().write_word(regs.read(reg_stack), ip);

      // push $ra
      regs.add(reg_stack, -sizeof(word_t));
      vm.get_mem().write_word(regs.read(reg_stack), regs.read(reg_return));

      word_t isr_ip = vm.get_mem().read_word(int_no * sizeof(word_t));
      if (isr_ip == 0) {
        // Check against 0 is fine because no code can reside under address 0.
        std::cout << "Interrupt " << int_no << " has been requested but ISR is missing, aborting VM..." << std::endl;
        vm.exit(1);
      }

      set_ip(isr_ip);
  }

  void cpu::raise_error(const word_t error_code) {
    perform_int(error_code);
  }
}
<|endoftext|>


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

#include "thread.h"
#include <kernel/kernel.h>
#include <kernel/thread-manager.h>
#include <kernel/mem-manager.h>
#include <kernel/engine.h>
#include <kernel/engines.h>
#include <kernel/platform.h>

namespace rt {

Thread::Thread(ThreadManager* thread_mgr, ResourceHandle<EngineThread> ethread)
    :	thread_mgr_(thread_mgr),
        type_(ethread.get()->type()),
        iv8_(nullptr),
        tpl_cache_(nullptr),
        stack_(GLOBAL_mem_manager()->virtual_allocator().AllocStack()),
        ethread_(ethread),
        exports_(this),
        ref_count_(0),
        terminate_(false),
        parent_promise_id_(0),
        runtime_(0) {
    priority_.Set(1);
}

Thread::~Thread() {
    RT_ASSERT(!"TODO: Make sure it's safe to delete thread object first!");
}

ExternalFunction* FunctionExports::Add(v8::Local<v8::Value> v,
                                       ResourceHandle<EngineThread> recv) {
    uint32_t index = data_.size();
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };
    RT_ASSERT(iv8);
    size_t export_id = ++export_id_;
    data_.push_back(std::move(FunctionExportData(iv8, v, export_id)));
    return new ExternalFunction(index, export_id, thread_, recv);
}

v8::Local<v8::Value> FunctionExports::Get(uint32_t index, size_t export_id) {
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };

    RT_ASSERT(index < data_.size());
    v8::EscapableHandleScope scope(iv8);
    if (data_[index].export_id() != export_id) {
        return scope.Escape(v8::Local<v8::Value>());
    }

    return scope.Escape(data_[index].GetValue(iv8));
}

void Thread::SetUp() {
    // Skip initialization for idle thread
    if (ThreadType::IDLE == type_) {
        return;
    }

    RT_ASSERT(nullptr == iv8_);
    RT_ASSERT(nullptr == tpl_cache_);
    iv8_ = v8::Isolate::New();
    iv8_->SetData(0, this);
    printf("[V8] new isolate\n");
    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);
    tpl_cache_ = new TemplateCache(iv8_);
}

void Thread::TearDown() {
    RT_ASSERT(ThreadType::DEFAULT == type_);
    RT_ASSERT(iv8_);
    RT_ASSERT(iv8_->GetData(0) == this);
    RT_ASSERT(tpl_cache_);

    {	v8::Isolate::Scope ivscope(iv8_);
        v8::HandleScope local_handle_scope(iv8_);

        auto promise_id = parent_promise_id();
        auto thread = parent_thread();

        LockingPtr<EngineThread> lptr { thread.get() };
        Thread* recv { lptr->thread() };
        RT_ASSERT(recv);

        TransportData data;
        if (!exit_value_.IsEmpty()) {
            TransportData::SerializeError err { data.MoveValue(this, recv,
                v8::Local<v8::Value>::New(iv8_, exit_value_)) };
        }

        {	std::unique_ptr<ThreadMessage> msg(new ThreadMessage(
                ThreadMessage::Type::FUNCTION_RETURN_RESOLVE,
                handle(),
                std::move(data), nullptr, promise_id));
            lptr->PushMessage(std::move(msg));
        }
    }

    RT_ASSERT(thread_mgr_);
    RT_ASSERT(this == thread_mgr_->current_thread());

    timeout_data_.Clear();
    irq_data_.Clear();
    promises_.Clear();

    printf("[V8] delete context\n");
    context_.Reset();
    args_.Reset();
    exit_value_.Reset();
    call_wrapper_.Reset();

    RT_ASSERT(tpl_cache_);
    delete tpl_cache_;

    RT_ASSERT(iv8_);
    printf("[V8] delete isolate\n");
    iv8_->Dispose(); // This deletes v8 isolate object

    type_ = ThreadType::TERMINATED;
}

v8::Local<v8::Object> Thread::GetIsolateGlobal() {
    v8::EscapableHandleScope scope(iv8_);
    auto s_isolate = v8::String::NewFromUtf8(iv8_, "isolate");

    auto context = v8::Local<v8::Context>::New(iv8_, context_);
    RT_ASSERT(!context.IsEmpty());
    auto isolate_value = context->Global()->Get(s_isolate);
    RT_ASSERT(!isolate_value.IsEmpty());
    RT_ASSERT(isolate_value->IsObject());
    return scope.Escape(isolate_value->ToObject());
}

bool Thread::Run() {
    // Not possible to run terminated thread
    RT_ASSERT(ThreadType::TERMINATED != type_);

    // Idle thread does nothing and never terminates
    if (ThreadType::IDLE == type_) {
        return true;
    }

    RT_ASSERT(iv8_);
    RT_ASSERT(tpl_cache_);

    uint64_t time_now { GLOBAL_platform()->BootTimeMicroseconds() };

    EngineThread::ThreadMessagesVector messages = ethread_.get()->TakeMessages();
    if (0 == messages.size()) {
        return true;
    }

    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);

    if (context_.IsEmpty()) {
        printf("[V8] new context\n");
        v8::Local<v8::Context> context = tpl_cache_->NewContext();
        context_ = std::move(v8::UniquePersistent<v8::Context>(iv8_, context));
    }

    RT_ASSERT(!context_.IsEmpty());
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(iv8_, context_);
    v8::Context::Scope cs(context);

    v8::TryCatch trycatch;

    for (ThreadMessage* message : messages) {
        if (nullptr == message) {
            continue; // Skip removed message
        }

        ThreadMessage::Type type = message->type();

        switch (type) {
        case ThreadMessage::Type::SET_ARGUMENTS_NOPARENT: {
            RT_ASSERT(args_.IsEmpty());
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            args_ = std::move(v8::UniquePersistent<v8::Value>(iv8_, unpacked));

            auto s_data = v8::String::NewFromUtf8(iv8_, "data");
            GetIsolateGlobal()->Set(s_data, unpacked);
        }
            break;
        case ThreadMessage::Type::SET_ARGUMENTS: {
            RT_ASSERT(args_.IsEmpty());
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            args_ = std::move(v8::UniquePersistent<v8::Value>(iv8_, unpacked));

            // Install args [isolate.data, isolate.env, isolate.system]
            auto s_data = v8::String::NewFromUtf8(iv8_, "data");
            auto s_env = v8::String::NewFromUtf8(iv8_, "env");
            auto s_system = v8::String::NewFromUtf8(iv8_, "system");
            auto isolate_obj = GetIsolateGlobal();
            RT_ASSERT(!unpacked.IsEmpty());
            RT_ASSERT(unpacked->IsArray());
            auto args_array = unpacked.As<v8::Array>();
            RT_ASSERT(3 == args_array->Length());
            isolate_obj->Set(s_data, args_array->Get(0));
            isolate_obj->Set(s_env, args_array->Get(1));
            isolate_obj->Set(s_system, args_array->Get(2));

            parent_thread_ = message->sender();
            parent_promise_id_ = message->recv_index();
        }
            break;
        case ThreadMessage::Type::EVALUATE: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());
            RT_ASSERT(unpacked->IsArray());
            v8::Local<v8::Array> arr { v8::Local<v8::Array>::Cast(unpacked) };
            v8::Local<v8::Value> code { arr->Get(0) };
            v8::Local<v8::Value> filename { arr->Get(1) };
            RT_ASSERT(code->IsString());
            RT_ASSERT(filename->IsString());

            v8::ScriptOrigin origin(filename);
            v8::ScriptCompiler::Source source(code->ToString(), origin);
            v8::Local<v8::Script> script = v8::ScriptCompiler::Compile(iv8_, &source,
                v8::ScriptCompiler::CompileOptions::kNoCompileOptions);
            if (!script.IsEmpty()) {
                script->Run();
            }
        }
            break;
        case ThreadMessage::Type::FUNCTION_CALL: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            ExternalFunction* efn { message->exported_func() };
            RT_ASSERT(efn);

            v8::Local<v8::Value> fnval { exports_.Get(efn->index(), efn->export_id()) };
            if (fnval.IsEmpty()) {
                fnval = v8::Null(iv8_);
            } else {
                RT_ASSERT(fnval->IsFunction());
            }

            {   RT_ASSERT(!call_wrapper_.IsEmpty());
                v8::Local<v8::Function> fnwrap { v8::Local<v8::Function>::New(iv8_, call_wrapper_) };
                v8::Local<v8::Value> argv[] {
                   fnval,
                   message->sender().NewExternal(iv8_),
                   unpacked,
                   v8::Uint32::NewFromUnsigned(iv8_, message->recv_index()),
                };
                fnwrap->Call(context->Global(), 4, argv);
            }
        }
            break;
        case ThreadMessage::Type::FUNCTION_RETURN_RESOLVE: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            v8::Local<v8::Promise::Resolver> resolver {
                v8::Local<v8::Promise::Resolver>::New(iv8_, TakePromise(message->recv_index())) };

            resolver->Resolve(unpacked);
            iv8_->RunMicrotasks();
        }
            break;
        case ThreadMessage::Type::FUNCTION_RETURN_REJECT: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            v8::Local<v8::Promise::Resolver> resolver {
                v8::Local<v8::Promise::Resolver>::New(iv8_, TakePromise(message->recv_index())) };

            resolver->Reject(unpacked);
            iv8_->RunMicrotasks();
        }
            break;
        case ThreadMessage::Type::TIMEOUT_EVENT: {
            auto recv_index = message->recv_index();
            RT_ASSERT(recv_index < std::numeric_limits<uint32_t>::max());
            uint32_t timeout_id { static_cast<uint32_t>(recv_index) };
            TimeoutData data(TakeTimeoutData(timeout_id));

            if (data.cleared()) {
                break;
            }

            auto fnv = data.GetCallback(iv8_);
            RT_ASSERT(!fnv.IsEmpty());
            RT_ASSERT(fnv->IsFunction());
            auto fn = fnv.As<v8::Function>();

            if (data.autoreset()) {
                // TODO: don't take timeout data in a first place
                thread_mgr_->SetTimeout(this, AddTimeoutData(std::move(data)), data.delay());
            }

            fn->Call(context->Global(), 0, nullptr);
        }
            break;
        case ThreadMessage::Type::IRQ_RAISE: {
            v8::Local<v8::Value> fnv { v8::Local<v8::Value>::New(iv8_,
                GetIRQData(message->recv_index())) };
            RT_ASSERT(fnv->IsFunction());
            v8::Local<v8::Function> fn { v8::Local<v8::Function>::Cast(fnv) };
            fn->Call(context->Global(), 0, nullptr);
        }
            break;
        case ThreadMessage::Type::EMPTY:
            break;
        default:
            RT_ASSERT(!"Unknown thread message");
            break;
        }

        if (!message->reusable()) {
            delete message;
        }
    }

    v8::Local<v8::Value> ex = trycatch.Exception();
    if (!ex.IsEmpty() && !trycatch.HasTerminated()) {
        v8::String::Utf8Value exception_str(ex);
        v8::Local<v8::Message> message = trycatch.Message();
        if (message.IsEmpty()) {
            printf("Uncaught exception: %s\n", *exception_str);
        } else {
            v8::String::Utf8Value script_name(message->GetScriptResourceName());
            int linenum = message->GetLineNumber();
            printf("Uncaught exception: %s:%i: %s\n", *script_name, linenum, *exception_str);
        }

        v8::String::Utf8Value stack(trycatch.StackTrace());
        if (stack.length() > 0) {
            printf("%s\n", *stack);
        }
    }

    trycatch.Reset();

    {   uint64_t time_now_end { GLOBAL_platform()->BootTimeMicroseconds() };
        RT_ASSERT(time_now_end >= time_now);
        uint64_t tick_runtime = time_now_end - time_now;
        runtime_ += tick_runtime;
    }

    if (0 == ref_count_ || terminate_) {
        if (terminate_) {
            printf("[ terminate thread (reason: isolate.exit() called) ]\n");
        } else {
            printf("[ terminate thread (reason: refcount 0) ]\n");
        }

        terminate_ = true;
        return false;
    }

    return true;
}

} // namespace rt
<commit_msg>remove new/delete context debug messages<commit_after>// Copyright 2014 Runtime.JS project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "thread.h"
#include <kernel/kernel.h>
#include <kernel/thread-manager.h>
#include <kernel/mem-manager.h>
#include <kernel/engine.h>
#include <kernel/engines.h>
#include <kernel/platform.h>

namespace rt {

Thread::Thread(ThreadManager* thread_mgr, ResourceHandle<EngineThread> ethread)
    :	thread_mgr_(thread_mgr),
        type_(ethread.get()->type()),
        iv8_(nullptr),
        tpl_cache_(nullptr),
        stack_(GLOBAL_mem_manager()->virtual_allocator().AllocStack()),
        ethread_(ethread),
        exports_(this),
        ref_count_(0),
        terminate_(false),
        parent_promise_id_(0),
        runtime_(0) {
    priority_.Set(1);
}

Thread::~Thread() {
    RT_ASSERT(!"TODO: Make sure it's safe to delete thread object first!");
}

ExternalFunction* FunctionExports::Add(v8::Local<v8::Value> v,
                                       ResourceHandle<EngineThread> recv) {
    uint32_t index = data_.size();
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };
    RT_ASSERT(iv8);
    size_t export_id = ++export_id_;
    data_.push_back(std::move(FunctionExportData(iv8, v, export_id)));
    return new ExternalFunction(index, export_id, thread_, recv);
}

v8::Local<v8::Value> FunctionExports::Get(uint32_t index, size_t export_id) {
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };

    RT_ASSERT(index < data_.size());
    v8::EscapableHandleScope scope(iv8);
    if (data_[index].export_id() != export_id) {
        return scope.Escape(v8::Local<v8::Value>());
    }

    return scope.Escape(data_[index].GetValue(iv8));
}

void Thread::SetUp() {
    // Skip initialization for idle thread
    if (ThreadType::IDLE == type_) {
        return;
    }

    RT_ASSERT(nullptr == iv8_);
    RT_ASSERT(nullptr == tpl_cache_);
    iv8_ = v8::Isolate::New();
    iv8_->SetData(0, this);
    printf("[V8] new isolate\n");
    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);
    tpl_cache_ = new TemplateCache(iv8_);
}

void Thread::TearDown() {
    RT_ASSERT(ThreadType::DEFAULT == type_);
    RT_ASSERT(iv8_);
    RT_ASSERT(iv8_->GetData(0) == this);
    RT_ASSERT(tpl_cache_);

    {	v8::Isolate::Scope ivscope(iv8_);
        v8::HandleScope local_handle_scope(iv8_);

        auto promise_id = parent_promise_id();
        auto thread = parent_thread();

        LockingPtr<EngineThread> lptr { thread.get() };
        Thread* recv { lptr->thread() };
        RT_ASSERT(recv);

        TransportData data;
        if (!exit_value_.IsEmpty()) {
            TransportData::SerializeError err { data.MoveValue(this, recv,
                v8::Local<v8::Value>::New(iv8_, exit_value_)) };
        }

        {	std::unique_ptr<ThreadMessage> msg(new ThreadMessage(
                ThreadMessage::Type::FUNCTION_RETURN_RESOLVE,
                handle(),
                std::move(data), nullptr, promise_id));
            lptr->PushMessage(std::move(msg));
        }
    }

    RT_ASSERT(thread_mgr_);
    RT_ASSERT(this == thread_mgr_->current_thread());

    timeout_data_.Clear();
    irq_data_.Clear();
    promises_.Clear();

    context_.Reset();
    args_.Reset();
    exit_value_.Reset();
    call_wrapper_.Reset();

    RT_ASSERT(tpl_cache_);
    delete tpl_cache_;

    RT_ASSERT(iv8_);
    printf("[V8] delete isolate\n");
    iv8_->Dispose(); // This deletes v8 isolate object

    type_ = ThreadType::TERMINATED;
}

v8::Local<v8::Object> Thread::GetIsolateGlobal() {
    v8::EscapableHandleScope scope(iv8_);
    auto s_isolate = v8::String::NewFromUtf8(iv8_, "isolate");

    auto context = v8::Local<v8::Context>::New(iv8_, context_);
    RT_ASSERT(!context.IsEmpty());
    auto isolate_value = context->Global()->Get(s_isolate);
    RT_ASSERT(!isolate_value.IsEmpty());
    RT_ASSERT(isolate_value->IsObject());
    return scope.Escape(isolate_value->ToObject());
}

bool Thread::Run() {
    // Not possible to run terminated thread
    RT_ASSERT(ThreadType::TERMINATED != type_);

    // Idle thread does nothing and never terminates
    if (ThreadType::IDLE == type_) {
        return true;
    }

    RT_ASSERT(iv8_);
    RT_ASSERT(tpl_cache_);

    uint64_t time_now { GLOBAL_platform()->BootTimeMicroseconds() };

    EngineThread::ThreadMessagesVector messages = ethread_.get()->TakeMessages();
    if (0 == messages.size()) {
        return true;
    }

    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);

    if (context_.IsEmpty()) {
        v8::Local<v8::Context> context = tpl_cache_->NewContext();
        context_ = std::move(v8::UniquePersistent<v8::Context>(iv8_, context));
    }

    RT_ASSERT(!context_.IsEmpty());
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(iv8_, context_);
    v8::Context::Scope cs(context);

    v8::TryCatch trycatch;

    for (ThreadMessage* message : messages) {
        if (nullptr == message) {
            continue; // Skip removed message
        }

        ThreadMessage::Type type = message->type();

        switch (type) {
        case ThreadMessage::Type::SET_ARGUMENTS_NOPARENT: {
            RT_ASSERT(args_.IsEmpty());
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            args_ = std::move(v8::UniquePersistent<v8::Value>(iv8_, unpacked));

            auto s_data = v8::String::NewFromUtf8(iv8_, "data");
            GetIsolateGlobal()->Set(s_data, unpacked);
        }
            break;
        case ThreadMessage::Type::SET_ARGUMENTS: {
            RT_ASSERT(args_.IsEmpty());
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            args_ = std::move(v8::UniquePersistent<v8::Value>(iv8_, unpacked));

            // Install args [isolate.data, isolate.env, isolate.system]
            auto s_data = v8::String::NewFromUtf8(iv8_, "data");
            auto s_env = v8::String::NewFromUtf8(iv8_, "env");
            auto s_system = v8::String::NewFromUtf8(iv8_, "system");
            auto isolate_obj = GetIsolateGlobal();
            RT_ASSERT(!unpacked.IsEmpty());
            RT_ASSERT(unpacked->IsArray());
            auto args_array = unpacked.As<v8::Array>();
            RT_ASSERT(3 == args_array->Length());
            isolate_obj->Set(s_data, args_array->Get(0));
            isolate_obj->Set(s_env, args_array->Get(1));
            isolate_obj->Set(s_system, args_array->Get(2));

            parent_thread_ = message->sender();
            parent_promise_id_ = message->recv_index();
        }
            break;
        case ThreadMessage::Type::EVALUATE: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());
            RT_ASSERT(unpacked->IsArray());
            v8::Local<v8::Array> arr { v8::Local<v8::Array>::Cast(unpacked) };
            v8::Local<v8::Value> code { arr->Get(0) };
            v8::Local<v8::Value> filename { arr->Get(1) };
            RT_ASSERT(code->IsString());
            RT_ASSERT(filename->IsString());

            v8::ScriptOrigin origin(filename);
            v8::ScriptCompiler::Source source(code->ToString(), origin);
            v8::Local<v8::Script> script = v8::ScriptCompiler::Compile(iv8_, &source,
                v8::ScriptCompiler::CompileOptions::kNoCompileOptions);
            if (!script.IsEmpty()) {
                script->Run();
            }
        }
            break;
        case ThreadMessage::Type::FUNCTION_CALL: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            ExternalFunction* efn { message->exported_func() };
            RT_ASSERT(efn);

            v8::Local<v8::Value> fnval { exports_.Get(efn->index(), efn->export_id()) };
            if (fnval.IsEmpty()) {
                fnval = v8::Null(iv8_);
            } else {
                RT_ASSERT(fnval->IsFunction());
            }

            {   RT_ASSERT(!call_wrapper_.IsEmpty());
                v8::Local<v8::Function> fnwrap { v8::Local<v8::Function>::New(iv8_, call_wrapper_) };
                v8::Local<v8::Value> argv[] {
                   fnval,
                   message->sender().NewExternal(iv8_),
                   unpacked,
                   v8::Uint32::NewFromUnsigned(iv8_, message->recv_index()),
                };
                fnwrap->Call(context->Global(), 4, argv);
            }
        }
            break;
        case ThreadMessage::Type::FUNCTION_RETURN_RESOLVE: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            v8::Local<v8::Promise::Resolver> resolver {
                v8::Local<v8::Promise::Resolver>::New(iv8_, TakePromise(message->recv_index())) };

            resolver->Resolve(unpacked);
            iv8_->RunMicrotasks();
        }
            break;
        case ThreadMessage::Type::FUNCTION_RETURN_REJECT: {
            v8::Local<v8::Value> unpacked { message->data().Unpack(this) };
            RT_ASSERT(!unpacked.IsEmpty());

            v8::Local<v8::Promise::Resolver> resolver {
                v8::Local<v8::Promise::Resolver>::New(iv8_, TakePromise(message->recv_index())) };

            resolver->Reject(unpacked);
            iv8_->RunMicrotasks();
        }
            break;
        case ThreadMessage::Type::TIMEOUT_EVENT: {
            auto recv_index = message->recv_index();
            RT_ASSERT(recv_index < std::numeric_limits<uint32_t>::max());
            uint32_t timeout_id { static_cast<uint32_t>(recv_index) };
            TimeoutData data(TakeTimeoutData(timeout_id));

            if (data.cleared()) {
                break;
            }

            auto fnv = data.GetCallback(iv8_);
            RT_ASSERT(!fnv.IsEmpty());
            RT_ASSERT(fnv->IsFunction());
            auto fn = fnv.As<v8::Function>();

            if (data.autoreset()) {
                // TODO: don't take timeout data in a first place
                thread_mgr_->SetTimeout(this, AddTimeoutData(std::move(data)), data.delay());
            }

            fn->Call(context->Global(), 0, nullptr);
        }
            break;
        case ThreadMessage::Type::IRQ_RAISE: {
            v8::Local<v8::Value> fnv { v8::Local<v8::Value>::New(iv8_,
                GetIRQData(message->recv_index())) };
            RT_ASSERT(fnv->IsFunction());
            v8::Local<v8::Function> fn { v8::Local<v8::Function>::Cast(fnv) };
            fn->Call(context->Global(), 0, nullptr);
        }
            break;
        case ThreadMessage::Type::EMPTY:
            break;
        default:
            RT_ASSERT(!"Unknown thread message");
            break;
        }

        if (!message->reusable()) {
            delete message;
        }
    }

    v8::Local<v8::Value> ex = trycatch.Exception();
    if (!ex.IsEmpty() && !trycatch.HasTerminated()) {
        v8::String::Utf8Value exception_str(ex);
        v8::Local<v8::Message> message = trycatch.Message();
        if (message.IsEmpty()) {
            printf("Uncaught exception: %s\n", *exception_str);
        } else {
            v8::String::Utf8Value script_name(message->GetScriptResourceName());
            int linenum = message->GetLineNumber();
            printf("Uncaught exception: %s:%i: %s\n", *script_name, linenum, *exception_str);
        }

        v8::String::Utf8Value stack(trycatch.StackTrace());
        if (stack.length() > 0) {
            printf("%s\n", *stack);
        }
    }

    trycatch.Reset();

    {   uint64_t time_now_end { GLOBAL_platform()->BootTimeMicroseconds() };
        RT_ASSERT(time_now_end >= time_now);
        uint64_t tick_runtime = time_now_end - time_now;
        runtime_ += tick_runtime;
    }

    if (0 == ref_count_ || terminate_) {
        if (terminate_) {
            printf("[ terminate thread (reason: isolate.exit() called) ]\n");
        } else {
            printf("[ terminate thread (reason: refcount 0) ]\n");
        }

        terminate_ = true;
        return false;
    }

    return true;
}

} // namespace rt
<|endoftext|>


<commit_before>/*
 * Only 16 bit PCM MONO supported now.
 */
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>

#define BUFFERSIZE 1 // Number of sample rates (ex. seconds)
#define MINWAVEFREQ 20 // Minimum frequency that we want to process
#define MAXSTEPS 2 // How many steps to skip when we are looking for silences'
#define MATCHME 7 // Matching this number of silences means success

using namespace std;

FILE * process_headers(const char*);
bool check_sample(const char*, const char*);
void dump_values(FILE * in);
void read_periods(const char*);
void read_cfg(const char*);
void fatal (const char* );

char errmsg[200]; // Temporary message
int SAMPLE_RATE, //
	DATA_SIZE,  // Data chunk size in bytes
	PROC_SAMPLES; // Minimum number of samples to process and be sure two waves included

map<string, string> cfg; // OK, ok... Is it possible to store any value but string (Rrrr...) here?

class Range {
	public:
		Range() { tm = tmin = tmax = 0; };
		Range(const double & a) { tm = a; tmin = a * 0.9; tmax = a * 1.1; }
		Range operator = (const double i) { return Range(i); }
		bool operator == (const double & i) const { return tmin < i && i < tmax; }
		bool operator == (const Range & r) const { return r == tm; }
		bool operator > (const double & i) const { return i > tmax; }
		bool operator > (const Range & r) const { return r > tm; }
		bool operator < (const double & i) const { return i < tmin; }
		bool operator < (const Range & r) const { return r < tm; }
	protected:
		int tmin, tm, tmax;
};
typedef list<pair<int,int> > ttrace;
class workitm {
	public:
		int len,a,b;
		workitm(int a, int b) { len = 0; this->a = a; this->b = b; }
		workitm() { len = a = b = 0; }
		int ami(int, int);
		ttrace trace;
};

// ------------------------------------------------------------
// This method finds a "good" value in the set and
// returns:
// 0 if element deleted
// 1 if it's a good element
// 2 if the search is over (pattern recognized)
//
int workitm::ami(const int a, const int b) {
	if (a - this->a > MAXSTEPS || b - this->b > MAXSTEPS) return 0;
	// ------------------------------------------------------------
	// Here we have a nice thing called success
	// We fit the "region" here. We either finished,
	// or just increasing len
	//
	// Hemm we should add some trace stuff here
	printf("Xa: %d, b: %d\n", a, b);
	trace.push_back(pair<int,int>(a,b)); // Segfault here...
	printf("Ya: %d, b: %d\n", a, b);
	return ++(this->len) < MATCHME? 1:2;
}

typedef multimap<Range,pair<int,double> > tvals;
typedef list<workitm> twork;

int main (int argc, char *argv[]) {

	if (argc < 3) {
		fatal ("Usage: ./a.out config.cfg sample.wav\n\nor\n"
				"./a.out config.cfg samplefile.txt catchable.wav");
	}
	read_cfg(argv[1]);
	// ------------------------------------------------------------
	// Only header given, we just dump out the silence values
	//
	if (argc == 3) {
		FILE * in = process_headers(argv[2]);
		dump_values(in);
	}
	// ------------------------------------------------------------
	// We have values file and a new samplefile. Let's rock
	//
	else if (argc == 4) {
		tvals vals;

		ifstream file;
		file.open(argv[2]);
		string line;
		int x;
		double tmp2;
		for (int i = 0; ! file.eof(); i++) {
			getline(file, line);
			x = line.find(";");
			if (x == -1) break;
			istringstream place(line.substr(0,x));
			istringstream range(line.substr(x+1));
			pair<Range,pair<int,double> > tmp;
			range >> tmp2;
			tmp.first = tmp2;
			place >> tmp.second.second;
			tmp.second.first = i;
			vals.insert(tmp);
		}
		// OK, we have it. Let's print?
		//for (vector<trange>::iterator it1 = vals.begin(); it1 != vals.end(); it1++) {
		//printf ("%.6f - %.6f\n", (*it1).first, (*it1).second);
		//}
		// ------------------------------------------------------------
		// Let's work with the seconds sample like with a stream
		//
		FILE * an = process_headers(argv[3]);
		// We can read and analyze it now
		// Trying to match in only first 15 seconds of the record

		short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
		istringstream i(cfg["treshold1"]);
		double treshold1;
		i >> treshold1;
		int min_silence = (int)((1 << 15) * treshold1), // Below this value we have "silence, pshhh..."
			found_s = 0,
			b = -1, // This is the found silence counter (starting with zero)
			head = 0;
		twork work;
		while (! feof(an) ) {
			fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, an);
			for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
				int cur = abs(buf[i]);

				if (cur <= min_silence) {
					found_s++;
				} else {
					if (found_s >= PROC_SAMPLES) {
						b++; // Increasing the number of silence counter (sort of current index)
						// Found a found_s/SAMPLE_RATE length silence
						// Let's look for an analogous thing in vals variable (original file)
						double sec = (double)found_s/SAMPLE_RATE;
						// Find sec in range
						pair<tvals::iterator, tvals::iterator> pa = vals.equal_range(sec);

						//------------------------------------------------------------
						// We put a indexes here that we use for continued threads
						// (we don't want to create a new "thread" with already
						// used length of a silence)
						//
						set<int> used_a;

						//------------------------------------------------------------
						// Iterating through samples that match the found silence
						//
						for (tvals::iterator in_a = pa.first; in_a != pa.second; in_a++)
						{
							int a = (*in_a).second.first;
							/*
							   printf("%7.4f<->%7.4f,     %.4f<->%.4f (%5.2f%%)\n",
							   vals[i].first, (double)(head-found_s)/SAMPLE_RATE,
							   vals[i].second.tm, sec,
							   vals[i].second.tm *100/sec-100);
							   */
							//------------------------------------------------------------
							// Check if it exists in our work array
							//
							for (twork::iterator w = work.begin(); w != work.end(); w++) {
								int r = w->ami(a,b);
								switch (r) {
									case 0: work.erase(w); break;
									case 1: used_a.insert(a); break;
									case 2: // We finished our work. Print the trace.
										printf("Found a matching pattern! Length: %d, here comes the trace:\n", 1);
											/*
										for (ttrace::iterator tr = w->trace.begin(); tr != w->trace.end(); tr++) {
											printf("%d %d\n", tr->first, tr->second);
										}
										*/
								}
							}
							if (used_a.find(a) == used_a.end()) {
								work.push_back(workitm(a,b));
							}
						}
						// Looking for another silence
						found_s = 0;
					}
				}
				head++;
			}
		}
	}
	exit(0);
}

void read_cfg (const char * filename) {
	ifstream file;
	file.open(filename);
	string line;
	int x;
	while (! file.eof() ) {
		getline(file, line);
		x = line.find(":");
		if (x == -1) break; // Last line, exit
		cfg[line.substr(0,x)] = line.substr(x+2);
	}
}

FILE * process_headers(const char * infile) {
	FILE * in = fopen(infile, "rb");

	// Read bytes [0-3] and [8-11], they should be "RIFF" and "WAVE" in ASCII
	char header[5];
	fread(header, 1, 4, in);

	char sample[] = "RIFF";
	if (! check_sample(sample, header) ) {
		fatal ("RIFF header not found, exiting\n");
	}
	// Checking for compression code (21'st byte is 01, 22'nd - 00, little-endian notation
	short int tmp[2]; // two-byte integer
	fseek(in, 0x14, 0); // offset = 20 bytes
	fread(&tmp, 2, 2, in); // Reading two two-byte samples (comp. code and no. of channels)
	if ( tmp[0] != 1 ) {
		sprintf(errmsg, "Only PCM(1) supported, compression code given: %d\n", tmp[0]);
		fatal (errmsg);
	}
	// Number of channels must be "MONO"
	if ( tmp[1] != 1 ) {
		printf(errmsg, "Only MONO supported, given number of channels: %d\n", tmp[1]);
		fatal (errmsg);
	}
	fread(&SAMPLE_RATE, 2, 1, in); // Single two-byte sample
	//printf ("Sample rate: %d\n", SAMPLE_RATE);
	PROC_SAMPLES = SAMPLE_RATE / MINWAVEFREQ;
	fseek(in, 0x24, 0);
	fread(header, 1, 4, in);
	strcpy(sample, "data");
	if (! check_sample(sample, header)) {
		fatal ("data chunk not found in byte offset=36, file corrupted.");
	}
	// Get data chunk size here
	fread(&DATA_SIZE, 4, 1, in); // Single two-byte sample
	//printf ("Datasize: %d bytes\n", DATA_SIZE);
	return in;
}

bool check_sample (const char * sample, const char * b) { // My STRCPY.
	for(int i = 0; i < sizeof(sample)-1; i++) {
		if (sample[i] != b[i]) {
			return false;
		}
	}
	return true;
}

void fatal (const char * msg) { // Print error message and exit
	perror (msg);
	exit (1);
}

void dump_values(FILE * in) {
	istringstream i(cfg["treshold1"]);
	double treshold1;
	i >> treshold1;
	// ------------------------------------------------------------
	// This "15" means we have 16 bits for signed, this means
	// 15 bits for unsigned int.
	int min_silence = (int)((1 << 15) * treshold1); // Below this value we have "silence, pshhh..."

	short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
	int head = 0, // Assume sample started
		found_s = 0; // Number of silence samples

	int first_silence = 0;

	while (! feof(in) ) {
		fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, in);
		for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
			int cur = abs(buf[i]);

			if (cur <= min_silence) {
				found_s++;
			} else {
				if (found_s >= PROC_SAMPLES) {
					printf("%.6f;%.6f\n", (double)(head-found_s)/SAMPLE_RATE, (double)found_s/SAMPLE_RATE);
				}
				found_s = 0;
			}
			head++;
		}
	}
}
<commit_msg>Mysterious segmentation fault error fixed! Woo-hoo!<commit_after>/*
 * Only 16 bit PCM MONO supported now.
 */
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>

#define BUFFERSIZE 1 // Number of sample rates (ex. seconds)
#define MINWAVEFREQ 20 // Minimum frequency that we want to process
#define MAXSTEPS 2 // How many steps to skip when we are looking for silences'
#define MATCHME 7 // Matching this number of silences means success

using namespace std;

FILE * process_headers(const char*);
bool check_sample(const char*, const char*);
void dump_values(FILE * in);
void read_periods(const char*);
void read_cfg(const char*);
void fatal (const char* );

char errmsg[200]; // Temporary message
int SAMPLE_RATE, //
	DATA_SIZE,  // Data chunk size in bytes
	PROC_SAMPLES; // Minimum number of samples to process and be sure two waves included

map<string, string> cfg; // OK, ok... Is it possible to store any value but string (Rrrr...) here?

class Range {
	public:
		Range() { tm = tmin = tmax = 0; };
		Range(const double & a) { tm = a; tmin = a * 0.9; tmax = a * 1.1; }
		Range operator = (const double i) { return Range(i); }
		bool operator == (const double & i) const { return tmin < i && i < tmax; }
		bool operator == (const Range & r) const { return r == tm; }
		bool operator > (const double & i) const { return i > tmax; }
		bool operator > (const Range & r) const { return r > tm; }
		bool operator < (const double & i) const { return i < tmin; }
		bool operator < (const Range & r) const { return r < tm; }
	protected:
		int tmin, tm, tmax;
};
class workitm {
	public:
		int len,a,b;
		workitm(int a, int b) { len = 0; this->a = a; this->b = b; }
		workitm() { len = a = b = 0; }
		int ami(int, int);
		list<pair<int, int> > trace;
};
// ------------------------------------------------------------
// This method finds a "good" value in the set and
// returns:
// 0 if element deleted
// 1 if it's a good element
// 2 if the search is over (pattern recognized)
//
int workitm::ami(const int a, const int b) {
	if (a - this->a > MAXSTEPS || b - this->b > MAXSTEPS) return 0;
	// ------------------------------------------------------------
	// Here we have a nice thing called success
	// We fit the "region" here. We either finished,
	// or just increasing len
	//
    trace.push_back(pair<int, int>(a,b));
	return ++(this->len) < MATCHME? 1:2;
}

typedef multimap<Range,pair<int,double> > tvals;

int main (int argc, char *argv[]) {
	if (argc < 3) {
		fatal ("Usage: ./a.out config.cfg sample.wav\n\nor\n"
				"./a.out config.cfg samplefile.txt catchable.wav");
	}
	read_cfg(argv[1]);
	// ------------------------------------------------------------
	// Only header given, we just dump out the silence values
	//
	if (argc == 3) {
		FILE * in = process_headers(argv[2]);
		dump_values(in);
	}
	// ------------------------------------------------------------
	// We have values file and a new samplefile. Let's rock
	//
	else if (argc == 4) {
		tvals vals;

		ifstream file;
		file.open(argv[2]);
		string line;
		int x;
		double tmp2;
		for (int i = 0; ! file.eof(); i++) {
			getline(file, line);
			x = line.find(";");
			if (x == -1) break;
			istringstream place(line.substr(0,x));
			istringstream range(line.substr(x+1));
			pair<Range,pair<int,double> > tmp;
			range >> tmp2;
			tmp.first = tmp2;
			place >> tmp.second.second;
			tmp.second.first = i;
			vals.insert(tmp);
		}
		// OK, we have it. Let's print?
		//for (vector<trange>::iterator it1 = vals.begin(); it1 != vals.end(); it1++) {
		//printf ("%.6f - %.6f\n", (*it1).first, (*it1).second);
		//}
		// ------------------------------------------------------------
		// Let's work with the seconds sample like with a stream
		//
		FILE * an = process_headers(argv[3]);
		// We can read and analyze it now
		// Trying to match in only first 15 seconds of the record

		short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
		istringstream i(cfg["treshold1"]);
		double treshold1;
		i >> treshold1;
		int min_silence = (int)((1 << 15) * treshold1), // Below this value we have "silence, pshhh..."
			found_s = 0,
			b = -1, // This is the found silence counter (starting with zero)
			head = 0;
		list<workitm> work;
		while (! feof(an) ) {
			fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, an);
			for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
				int cur = abs(buf[i]);

				if (cur <= min_silence) {
					found_s++;
				} else {
					if (found_s >= PROC_SAMPLES) {
						b++; // Increasing the number of silence counter (sort of current index)
						// Found a found_s/SAMPLE_RATE length silence
						// Let's look for an analogous thing in vals variable (original file)
						double sec = (double)found_s/SAMPLE_RATE;
						// Find sec in range
						pair<tvals::iterator, tvals::iterator> pa = vals.equal_range(sec);

						//------------------------------------------------------------
						// We put a indexes here that we use for continued threads
						// (we don't want to create a new "thread" with already
						// used length of a silence)
						//
						set<int> used_a;

						//------------------------------------------------------------
						// Iterating through samples that match the found silence
						//
						for (tvals::iterator in_a = pa.first; in_a != pa.second; in_a++)
						{
							int a = in_a->second.first;
							/*
							   printf("%7.4f<->%7.4f,     %.4f<->%.4f (%5.2f%%)\n",
							   vals[i].first, (double)(head-found_s)/SAMPLE_RATE,
							   vals[i].second.tm, sec,
							   vals[i].second.tm *100/sec-100);
							   */
							//------------------------------------------------------------
							// Check if it exists in our work array
							//
							for (list<workitm>::iterator w = work.begin(); w != work.end(); w++) {
								int r = w->ami(a,b);
								switch (r) {
									case 0: work.erase(w); w = work.begin(); break;
									case 1: used_a.insert(a); break;
									case 2: // We finished our work. Print the trace.
										printf("Found a matching pattern! Length: %d, here comes the trace:\n", 1);
                                        for (list<pair<int,int> >::iterator tr = w->trace.begin(); tr != w->trace.end(); tr++) {
                                            printf("%d %d\n", tr->first, tr->second);
                                        }
                                        break;
								}
							}
							if (used_a.find(a) == used_a.end()) {
								work.push_back(workitm(a,b));
							}
						}
						// Looking for another silence
						found_s = 0;
					}
				}
				head++;
			}
		}
	}
	exit(0);
}

void read_cfg (const char * filename) {
	ifstream file;
	file.open(filename);
	string line;
	int x;
	while (! file.eof() ) {
		getline(file, line);
		x = line.find(":");
		if (x == -1) break; // Last line, exit
		cfg[line.substr(0,x)] = line.substr(x+2);
	}
}

FILE * process_headers(const char * infile) {
	FILE * in = fopen(infile, "rb");

	// Read bytes [0-3] and [8-11], they should be "RIFF" and "WAVE" in ASCII
	char header[5];
	fread(header, 1, 4, in);

	char sample[] = "RIFF";
	if (! check_sample(sample, header) ) {
		fatal ("RIFF header not found, exiting\n");
	}
	// Checking for compression code (21'st byte is 01, 22'nd - 00, little-endian notation
	short int tmp[2]; // two-byte integer
	fseek(in, 0x14, 0); // offset = 20 bytes
	fread(&tmp, 2, 2, in); // Reading two two-byte samples (comp. code and no. of channels)
	if ( tmp[0] != 1 ) {
		sprintf(errmsg, "Only PCM(1) supported, compression code given: %d\n", tmp[0]);
		fatal (errmsg);
	}
	// Number of channels must be "MONO"
	if ( tmp[1] != 1 ) {
		printf(errmsg, "Only MONO supported, given number of channels: %d\n", tmp[1]);
		fatal (errmsg);
	}
	fread(&SAMPLE_RATE, 2, 1, in); // Single two-byte sample
	//printf ("Sample rate: %d\n", SAMPLE_RATE);
	PROC_SAMPLES = SAMPLE_RATE / MINWAVEFREQ;
	fseek(in, 0x24, 0);
	fread(header, 1, 4, in);
	strcpy(sample, "data");
	if (! check_sample(sample, header)) {
		fatal ("data chunk not found in byte offset=36, file corrupted.");
	}
	// Get data chunk size here
	fread(&DATA_SIZE, 4, 1, in); // Single two-byte sample
	//printf ("Datasize: %d bytes\n", DATA_SIZE);
	return in;
}

bool check_sample (const char * sample, const char * b) { // My STRCPY.
	for(int i = 0; i < sizeof(sample)-1; i++) {
		if (sample[i] != b[i]) {
			return false;
		}
	}
	return true;
}

void fatal (const char * msg) { // Print error message and exit
	perror (msg);
	exit (1);
}

void dump_values(FILE * in) {
	istringstream i(cfg["treshold1"]);
	double treshold1;
	i >> treshold1;
	// ------------------------------------------------------------
	// This "15" means we have 16 bits for signed, this means
	// 15 bits for unsigned int.
	int min_silence = (int)((1 << 15) * treshold1); // Below this value we have "silence, pshhh..."

	short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
	int head = 0, // Assume sample started
		found_s = 0; // Number of silence samples

	int first_silence = 0;

	while (! feof(in) ) {
		fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, in);
		for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
			int cur = abs(buf[i]);

			if (cur <= min_silence) {
				found_s++;
			} else {
				if (found_s >= PROC_SAMPLES) {
					printf("%.6f;%.6f\n", (double)(head-found_s)/SAMPLE_RATE, (double)found_s/SAMPLE_RATE);
				}
				found_s = 0;
			}
			head++;
		}
	}
}
<|endoftext|>


<commit_before>#include <chrono>
#include <cstdint>
#include <exception>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>

#include <tudocomp/Compressor.hpp>
#include <tudocomp/io.hpp>
#include <tudocomp/io/IOUtil.hpp>
#include <tudocomp_driver/Registry.hpp>

/*namespace validate {
  static bool algorithm(const char* flagname, int32 value) {
    if (value > 0 && value < 32768)   // value is ok
      return true;
    printf("Invalid value for --%s: %d\n", flagname, (int)value);
    return false;
  }
  static const bool algorithm_dummy = RegisterFlagValidator(&FLAGS_algorithm, &algorithm);
}*/

DEFINE_string(algorithm, "", "Algorithm to use for (de)compression. See --list for a complete list of them.");
DEFINE_bool(decompress, false, "Decompress input instead of compressing it.");
DEFINE_string(output, "", "Choose output filename instead the the default generated one of <input>.tdc or stdout.");
DEFINE_bool(stats, false, "Print statistics to stdout.");
DEFINE_bool(force, false, "Overwrite output even if it exists.");
DEFINE_bool(list, false, "List all compression algorithms supported by this tool.");
DEFINE_bool(raw, false, "Do not emit an header into the output file when compressing.");
DEFINE_bool(usestdin, false, "Read from stdin instead of trying to open a file.");
DEFINE_bool(usestdout, false, "Output to stdout instead of writing to a file");

namespace tdc_driver {

using namespace tdc;
using namespace tdc_algorithms;

const std::string COMPRESSED_FILE_ENDING = "tdc";

static void exit(std::string msg) {
    // TODO: Replace with more specific logic-error-exception
    throw std::runtime_error(msg);
}

static void validate_flag_combination() {
    auto err = [](std::string s) {
        exit(s);
    };

    if (!FLAGS_list) {
        if (!FLAGS_decompress && (std::string(FLAGS_algorithm) == "")) {
            err("Need to give an algorithm for compression");
        }
        if (FLAGS_decompress && FLAGS_raw && (std::string(FLAGS_algorithm) == "")) {
            err("Need to give an algorithm for raw decompression");
        }
    }
}

static bool fexists(std::string filename)
{
  std::ifstream ifile(filename);
  return bool(ifile);
}

static bool check_for_file_already_exist(std::string& ofile,
                                         bool allow_overwrite) {
    // Don't accidentially overwrite files
    if (!allow_overwrite && fexists(ofile)) {
        std::cerr << "Outputfile already exists\n";
        return false;
    }
    return true;
}

} // namespace tdc_driver

#include <iomanip>

int main(int argc, char** argv)
{
    using namespace tdc_driver;
    using namespace tdc_algorithms;

    google::InitGoogleLogging(argv[0]);
    google::SetUsageMessage("This tool compresses and decompresses files");
    if(argc == 1 || strcmp(argv[1],"-h") == 0 || strcmp(argv[1],"--help") == 0 || strcmp(argv[1],"-help") == 0) {
//        google::ShowUsageWithFlagsRestrict(argv[0], __FILE__); //shortcut
        std::vector<google::CommandLineFlagInfo> info;
        google::GetAllFlags(&info);

        std::cout << argv[0] << " [options] {file to compress/decompress}" << std::endl;
        std::cout << "You need to provide at least an algorithm and a source (a file) to compress/decompress." << std::endl << std::endl;
        std::cout
            << std::setw(20) << std::setiosflags(std::ios::left) << "Parameter"
            << std::setw(10) << "Type"
            << std::setw(20) << "Default"
            << "Description" << std::endl;
        std::cout << std::endl;
         for(auto it = info.cbegin(); it != info.cend(); ++it) {
             if(it->filename != __FILE__) continue;
                 std::cout
                    << std::setw(20) << std::setiosflags(std::ios::left)<< (std::string("--")+ it->name)
                    << std::setw(10) << it->type
                    << std::setw(20) << (std::string("(") + it->default_value + ")")
                    << it->description << std::endl;
         }
        return 0;
    }

    int first_cmd_arg = google::ParseCommandLineFlags(&argc, &argv, true);

    try {
        validate_flag_combination();

        // Set up algorithms
        Registry& registry = REGISTRY;

        if (FLAGS_list) {
            std::cout << "This build supports the following algorithms:\n";
            std::cout << std::endl;
            std::cout << registry.generate_doc_string();

            return 0;
        }

        bool print_stats = FLAGS_stats;
        int alphabet_size = 0;

        bool do_compress = !FLAGS_decompress;

        /////////////////////////////////////////////////////////////////////////
        // Select algorithm

        bool do_raw = FLAGS_raw;

        class Selection {
            std::string m_id_string;
            std::unique_ptr<Compressor> m_compressor;
            bool m_needs_sentinel_terminator;
            std::shared_ptr<EnvRoot> m_algorithm_env;
        public:
            Selection():
                m_id_string(),
                m_compressor(),
                m_needs_sentinel_terminator(false),
                m_algorithm_env() {}
            Selection(std::string&& id_string,
                      std::unique_ptr<Compressor>&& compressor,
                      bool needs_sentinel_terminator,
                      std::shared_ptr<EnvRoot>&& algorithm_env):
                m_id_string(std::move(id_string)),
                m_compressor(std::move(compressor)),
                m_needs_sentinel_terminator(needs_sentinel_terminator),
                m_algorithm_env(std::move(algorithm_env)) {}
            const std::string& id_string() const {
                return m_id_string;
            }
            Compressor& compressor() {
                return *m_compressor;
            }
            bool needs_sentinel_terminator() const {
                return m_needs_sentinel_terminator;
            }
            const std::shared_ptr<EnvRoot>& algorithm_env() const {
                return m_algorithm_env;
            }
        };
        Selection selection;

        if (!FLAGS_algorithm.empty()) {
            auto id_string = FLAGS_algorithm;

            auto av = registry.parse_algorithm_id(id_string);
            auto needs_sentinel_terminator = av.needs_sentinel_terminator();
            auto compressor = registry.select_algorithm_or_exit(av);
            auto algorithm_env = compressor->env().root();

            selection = Selection {
                std::move(id_string),
                std::move(compressor),
                needs_sentinel_terminator,
                std::move(algorithm_env),
            };
        }

        /////////////////////////////////////////////////////////////////////////
        // Select where the input comes from

        std::string file;

        if ((!FLAGS_usestdin) && (first_cmd_arg < argc)) {
            file = argv[first_cmd_arg];
            if (!fexists(file)) {
                std::cerr << "input file " << file << " does not exist\n";
                return 1;
            }
        } else if (!FLAGS_usestdin) {
            std::cerr << "No input file given\n";
            return 1;
        }

        bool use_stdin = FLAGS_usestdin;

        /////////////////////////////////////////////////////////////////////////
        // Select where the output goes to

        std::string ofile;
        bool use_stdout = FLAGS_usestdout;
        bool use_explict_output = std::string(FLAGS_output) != "" ;

        if (use_explict_output) {
            // Output to manually specifed file
            ofile = FLAGS_output;
        } else if (!use_stdin && do_compress) {
            // Output to a automatically determined file
            ofile = file + "." + COMPRESSED_FILE_ENDING;
        } else if (!use_stdin && !do_compress && !use_stdout) {
            std::cerr << "Need to specify a output filename\n";
            return 1;
        }

        /////////////////////////////////////////////////////////////////////////
        // open streams

        using clk = std::chrono::high_resolution_clock;

        clk::time_point start_time = clk::now();
        clk::time_point setup_time;
        clk::time_point comp_time;
        clk::time_point end_time;

        {
            std::vector<uint8_t> stream_buffer;
            Input inp;

            if (use_stdin) {
                // Input from stdin
                inp = Input(std::cin);
            } else {
                // Input from specified file
                inp = Input::from_path(file);
            }

            Output out;
            if (use_stdout) {
                // Output to stdout
                out = Output::from_stream(std::cout);
            } else {
                // Output to specified file
                bool force = FLAGS_force;
                if (!check_for_file_already_exist(ofile, force)) {
                    return 1;
                } else {
                    out = Output::from_path(ofile, true);
                }
            }

            /////////////////////////////////////////////////////////////////////////
            // call into actual library

            if (do_compress) {
                if (print_stats) {
                    alphabet_size = 0; // count_alphabet_size(inp_vec);
                }

                if (!do_raw) {
                    CHECK(selection.id_string().find('%') == std::string::npos);

                    auto o_stream = out.as_stream();
                    o_stream << selection.id_string() << '%';
                }

                if (selection.needs_sentinel_terminator()) {
                    inp.escape_and_terminate();
                }

                selection.algorithm_env()->restart_stats("Compress");
                setup_time = clk::now();
                selection.compressor().compress(inp, out);
                comp_time = clk::now();
            } else {
                if ((!do_raw) && (selection.id_string().empty())) {
                    DLOG(INFO) << "Using header id string\n";
                    auto i_stream = inp.as_stream();
                    std::string algorithm_header;

                    char c;
                    size_t sanity_size_check = 0;
                    bool err = false;
                    while (i_stream.get(c)) {
                        err = false;
                        if (sanity_size_check > 1023) {
                            err = true;
                            break;
                        } else if (c == '%') {
                            break;
                        } else {
                            algorithm_header.push_back(c);
                        }
                        sanity_size_check++;
                        err = true;
                    }
                    if (err) {
                        exit("Input did not have an algorithm header!");
                    }

                    auto id_string = std::move(algorithm_header);
                    auto av = registry.parse_algorithm_id(id_string);
                    auto compressor = registry.select_algorithm_or_exit(av);
                    auto needs_sentinel_terminator = av.needs_sentinel_terminator();
                    auto algorithm_env = compressor->env().root();

                    selection = Selection {
                        std::move(id_string),
                        std::move(compressor),
                        needs_sentinel_terminator,
                        std::move(algorithm_env),
                    };
                } else {
                    DLOG(INFO) << "Using given id string\n";
                }

                if (selection.needs_sentinel_terminator()) {
                    out.unescape_and_trim();
                }

                selection.algorithm_env()->restart_stats("Decompress");
                setup_time = clk::now();
                selection.compressor().decompress(inp, out);
                comp_time = clk::now();
            }
        }

        auto algo_stats = selection.algorithm_env()->finish_stats();
        end_time = clk::now();

        if (print_stats) {
            auto setup_duration = setup_time - start_time;
            auto comp_duration = comp_time - setup_time;
            auto end_duration = end_time - comp_time;
            std::cout << "---------------\n";
            std::cout << "Config: " << selection.id_string() << std::endl;
            std::cout << "---------------\n";
            auto inp_size = 0;
            if (use_stdin) {
                std::cout << "input: <stdin>\n";
                std::cout << "input size: ? B\n";
            } else {
                inp_size = io::read_file_size(file);
                std::cout << "input: "<<file<<"\n";
                std::cout << "input size: "<<inp_size<<" B\n";
            }
            std::cout << "alphabet size: " << alphabet_size << "\n";

            auto out_size = 0;
            if (use_stdout) {
                std::cout << "output: <stdout>\n";
                std::cout << "output size: ? B\n";
            } else {
                out_size = io::read_file_size(ofile);
                std::cout << "output: "<<ofile<<"\n";
                std::cout << "output size: "<<out_size<<" B\n";
            }
            std::cout << "---------------\n";
            if (inp_size != 0) {
                std::cout << "compress rate: "<<(double(out_size)/double(inp_size) * 100)<<"%\n";
            }

            auto print_time = [] (std::string s, decltype(setup_duration)& t) {
                std::chrono::seconds sec(1);
                std::chrono::milliseconds milsec(1);
                std::chrono::microseconds micsec(1);
                using dur = std::chrono::duration<float>;
                using mildur = std::chrono::duration<float, std::milli>;
                using micdur = std::chrono::duration<float, std::micro>;

                if (t < milsec) {
                    auto ct = std::chrono::duration_cast<micdur>(t).count();
                    std::cout << s <<" time: "<< ct << " µs\n";
                } else if (t < sec) {
                    auto ct = std::chrono::duration_cast<mildur>(t).count();
                    std::cout << s <<" time: "<< ct << " ms\n";
                } else {
                    auto ct = std::chrono::duration_cast<dur>(t).count();
                    std::cout << s <<" time: "<< ct << " s\n";
                }
            };

            std::cout << "---------------\n";
            std::cout << "Algorithm Stats:\n";
            algo_stats.to_json(std::cout); //TODO text output
            std::cout << "\n";
            std::cout << "---------------\n";
            print_time("startup", setup_duration);
            print_time("compression", comp_duration);
            print_time("teardown", end_duration);
            std::cout << "---------------\n";
        }
    } catch (std::exception& e) {
        std::cout << "Error: " << e.what() << '\n';
        return 1;
    }

    return 0;
}
<commit_msg>Fix header-skipping logc in driver<commit_after>#include <chrono>
#include <cstdint>
#include <exception>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>

#include <tudocomp/Compressor.hpp>
#include <tudocomp/io.hpp>
#include <tudocomp/io/IOUtil.hpp>
#include <tudocomp_driver/Registry.hpp>

/*namespace validate {
  static bool algorithm(const char* flagname, int32 value) {
    if (value > 0 && value < 32768)   // value is ok
      return true;
    printf("Invalid value for --%s: %d\n", flagname, (int)value);
    return false;
  }
  static const bool algorithm_dummy = RegisterFlagValidator(&FLAGS_algorithm, &algorithm);
}*/

DEFINE_string(algorithm, "", "Algorithm to use for (de)compression. See --list for a complete list of them.");
DEFINE_bool(decompress, false, "Decompress input instead of compressing it.");
DEFINE_string(output, "", "Choose output filename instead the the default generated one of <input>.tdc or stdout.");
DEFINE_bool(stats, false, "Print statistics to stdout.");
DEFINE_bool(force, false, "Overwrite output even if it exists.");
DEFINE_bool(list, false, "List all compression algorithms supported by this tool.");
DEFINE_bool(raw, false, "Do not emit an header into the output file when compressing.");
DEFINE_bool(usestdin, false, "Read from stdin instead of trying to open a file.");
DEFINE_bool(usestdout, false, "Output to stdout instead of writing to a file");

namespace tdc_driver {

using namespace tdc;
using namespace tdc_algorithms;

const std::string COMPRESSED_FILE_ENDING = "tdc";

static void exit(std::string msg) {
    // TODO: Replace with more specific logic-error-exception
    throw std::runtime_error(msg);
}

static void validate_flag_combination() {
    auto err = [](std::string s) {
        exit(s);
    };

    if (!FLAGS_list) {
        if (!FLAGS_decompress && (std::string(FLAGS_algorithm) == "")) {
            err("Need to give an algorithm for compression");
        }
        if (FLAGS_decompress && FLAGS_raw && (std::string(FLAGS_algorithm) == "")) {
            err("Need to give an algorithm for raw decompression");
        }
    }
}

static bool fexists(std::string filename)
{
  std::ifstream ifile(filename);
  return bool(ifile);
}

static bool check_for_file_already_exist(std::string& ofile,
                                         bool allow_overwrite) {
    // Don't accidentially overwrite files
    if (!allow_overwrite && fexists(ofile)) {
        std::cerr << "Outputfile already exists\n";
        return false;
    }
    return true;
}

} // namespace tdc_driver

#include <iomanip>

int main(int argc, char** argv)
{
    using namespace tdc_driver;
    using namespace tdc_algorithms;

    google::InitGoogleLogging(argv[0]);
    google::SetUsageMessage("This tool compresses and decompresses files");
    if(argc == 1 || strcmp(argv[1],"-h") == 0 || strcmp(argv[1],"--help") == 0 || strcmp(argv[1],"-help") == 0) {
//        google::ShowUsageWithFlagsRestrict(argv[0], __FILE__); //shortcut
        std::vector<google::CommandLineFlagInfo> info;
        google::GetAllFlags(&info);

        std::cout << argv[0] << " [options] {file to compress/decompress}" << std::endl;
        std::cout << "You need to provide at least an algorithm and a source (a file) to compress/decompress." << std::endl << std::endl;
        std::cout
            << std::setw(20) << std::setiosflags(std::ios::left) << "Parameter"
            << std::setw(10) << "Type"
            << std::setw(20) << "Default"
            << "Description" << std::endl;
        std::cout << std::endl;
         for(auto it = info.cbegin(); it != info.cend(); ++it) {
             if(it->filename != __FILE__) continue;
                 std::cout
                    << std::setw(20) << std::setiosflags(std::ios::left)<< (std::string("--")+ it->name)
                    << std::setw(10) << it->type
                    << std::setw(20) << (std::string("(") + it->default_value + ")")
                    << it->description << std::endl;
         }
        return 0;
    }

    int first_cmd_arg = google::ParseCommandLineFlags(&argc, &argv, true);

    try {
        validate_flag_combination();

        // Set up algorithms
        Registry& registry = REGISTRY;

        if (FLAGS_list) {
            std::cout << "This build supports the following algorithms:\n";
            std::cout << std::endl;
            std::cout << registry.generate_doc_string();

            return 0;
        }

        bool print_stats = FLAGS_stats;
        int alphabet_size = 0;

        bool do_compress = !FLAGS_decompress;
        bool do_raw = FLAGS_raw;

        /////////////////////////////////////////////////////////////////////////
        // Select algorithm

        class Selection {
            std::string m_id_string;
            std::unique_ptr<Compressor> m_compressor;
            bool m_needs_sentinel_terminator;
            std::shared_ptr<EnvRoot> m_algorithm_env;
        public:
            Selection():
                m_id_string(),
                m_compressor(),
                m_needs_sentinel_terminator(false),
                m_algorithm_env() {}
            Selection(std::string&& id_string,
                      std::unique_ptr<Compressor>&& compressor,
                      bool needs_sentinel_terminator,
                      std::shared_ptr<EnvRoot>&& algorithm_env):
                m_id_string(std::move(id_string)),
                m_compressor(std::move(compressor)),
                m_needs_sentinel_terminator(needs_sentinel_terminator),
                m_algorithm_env(std::move(algorithm_env)) {}
            const std::string& id_string() const {
                return m_id_string;
            }
            Compressor& compressor() {
                return *m_compressor;
            }
            bool needs_sentinel_terminator() const {
                return m_needs_sentinel_terminator;
            }
            const std::shared_ptr<EnvRoot>& algorithm_env() const {
                return m_algorithm_env;
            }
        };
        Selection selection;

        if (!FLAGS_algorithm.empty()) {
            auto id_string = FLAGS_algorithm;

            auto av = registry.parse_algorithm_id(id_string);
            auto needs_sentinel_terminator = av.needs_sentinel_terminator();
            auto compressor = registry.select_algorithm_or_exit(av);
            auto algorithm_env = compressor->env().root();

            selection = Selection {
                std::move(id_string),
                std::move(compressor),
                needs_sentinel_terminator,
                std::move(algorithm_env),
            };
        }

        /////////////////////////////////////////////////////////////////////////
        // Select where the input comes from

        std::string file;

        if ((!FLAGS_usestdin) && (first_cmd_arg < argc)) {
            file = argv[first_cmd_arg];
            if (!fexists(file)) {
                std::cerr << "input file " << file << " does not exist\n";
                return 1;
            }
        } else if (!FLAGS_usestdin) {
            std::cerr << "No input file given\n";
            return 1;
        }

        bool use_stdin = FLAGS_usestdin;

        /////////////////////////////////////////////////////////////////////////
        // Select where the output goes to

        std::string ofile;
        bool use_stdout = FLAGS_usestdout;
        bool use_explict_output = std::string(FLAGS_output) != "" ;

        if (use_explict_output) {
            // Output to manually specifed file
            ofile = FLAGS_output;
        } else if (!use_stdin && do_compress) {
            // Output to a automatically determined file
            ofile = file + "." + COMPRESSED_FILE_ENDING;
        } else if (!use_stdin && !do_compress && !use_stdout) {
            std::cerr << "Need to specify a output filename\n";
            return 1;
        }

        /////////////////////////////////////////////////////////////////////////
        // open streams

        using clk = std::chrono::high_resolution_clock;

        clk::time_point start_time = clk::now();
        clk::time_point setup_time;
        clk::time_point comp_time;
        clk::time_point end_time;

        {
            std::vector<uint8_t> stream_buffer;
            Input inp;

            if (use_stdin) {
                // Input from stdin
                inp = Input(std::cin);
            } else {
                // Input from specified file
                inp = Input::from_path(file);
            }

            Output out;
            if (use_stdout) {
                // Output to stdout
                out = Output::from_stream(std::cout);
            } else {
                // Output to specified file
                bool force = FLAGS_force;
                if (!check_for_file_already_exist(ofile, force)) {
                    return 1;
                } else {
                    out = Output::from_path(ofile, true);
                }
            }

            /////////////////////////////////////////////////////////////////////////
            // call into actual library

            if (do_compress) {
                if (print_stats) {
                    alphabet_size = 0; // count_alphabet_size(inp_vec);
                }

                if (!do_raw) {
                    CHECK(selection.id_string().find('%') == std::string::npos);

                    auto o_stream = out.as_stream();
                    o_stream << selection.id_string() << '%';
                }

                if (selection.needs_sentinel_terminator()) {
                    inp.escape_and_terminate();
                }

                selection.algorithm_env()->restart_stats("Compress");
                setup_time = clk::now();
                selection.compressor().compress(inp, out);
                comp_time = clk::now();
            } else {
                // 3 cases
                // --decompress                   : read and use header
                // --decompress --algorithm       : read but ignore header
                // --decompress --raw --algorithm : no header

                std::string algorithm_header;

                if (!do_raw) {
                    // read header
                    auto i_stream = inp.as_stream();

                    char c;
                    size_t sanity_size_check = 0;
                    bool err = false;
                    while (i_stream.get(c)) {
                        err = false;
                        if (sanity_size_check > 1023) {
                            err = true;
                            break;
                        } else if (c == '%') {
                            break;
                        } else {
                            algorithm_header.push_back(c);
                        }
                        sanity_size_check++;
                        err = true;
                    }
                    if (err) {
                        exit("Input did not have an algorithm header!");
                    }
                }

                if (!do_raw && !selection.id_string().empty()) {
                    DLOG(INFO) << "Ignoring header " << algorithm_header
                        << " and using manually given " << selection.id_string();
                } else if (!do_raw) {
                    DLOG(INFO) << "Using header id string " << algorithm_header;

                    auto id_string = std::move(algorithm_header);
                    auto av = registry.parse_algorithm_id(id_string);
                    auto compressor = registry.select_algorithm_or_exit(av);
                    auto needs_sentinel_terminator = av.needs_sentinel_terminator();
                    auto algorithm_env = compressor->env().root();

                    selection = Selection {
                        std::move(id_string),
                        std::move(compressor),
                        needs_sentinel_terminator,
                        std::move(algorithm_env),
                    };
                } else {
                    DLOG(INFO) << "Using manually given " << selection.id_string();
                }

                if (selection.needs_sentinel_terminator()) {
                    out.unescape_and_trim();
                }

                selection.algorithm_env()->restart_stats("Decompress");
                setup_time = clk::now();
                selection.compressor().decompress(inp, out);
                comp_time = clk::now();
            }
        }

        auto algo_stats = selection.algorithm_env()->finish_stats();
        end_time = clk::now();

        if (print_stats) {
            auto setup_duration = setup_time - start_time;
            auto comp_duration = comp_time - setup_time;
            auto end_duration = end_time - comp_time;
            std::cout << "---------------\n";
            std::cout << "Config: " << selection.id_string() << std::endl;
            std::cout << "---------------\n";
            auto inp_size = 0;
            if (use_stdin) {
                std::cout << "input: <stdin>\n";
                std::cout << "input size: ? B\n";
            } else {
                inp_size = io::read_file_size(file);
                std::cout << "input: "<<file<<"\n";
                std::cout << "input size: "<<inp_size<<" B\n";
            }
            std::cout << "alphabet size: " << alphabet_size << "\n";

            auto out_size = 0;
            if (use_stdout) {
                std::cout << "output: <stdout>\n";
                std::cout << "output size: ? B\n";
            } else {
                out_size = io::read_file_size(ofile);
                std::cout << "output: "<<ofile<<"\n";
                std::cout << "output size: "<<out_size<<" B\n";
            }
            std::cout << "---------------\n";
            if (inp_size != 0) {
                std::cout << "compress rate: "<<(double(out_size)/double(inp_size) * 100)<<"%\n";
            }

            auto print_time = [] (std::string s, decltype(setup_duration)& t) {
                std::chrono::seconds sec(1);
                std::chrono::milliseconds milsec(1);
                std::chrono::microseconds micsec(1);
                using dur = std::chrono::duration<float>;
                using mildur = std::chrono::duration<float, std::milli>;
                using micdur = std::chrono::duration<float, std::micro>;

                if (t < milsec) {
                    auto ct = std::chrono::duration_cast<micdur>(t).count();
                    std::cout << s <<" time: "<< ct << " µs\n";
                } else if (t < sec) {
                    auto ct = std::chrono::duration_cast<mildur>(t).count();
                    std::cout << s <<" time: "<< ct << " ms\n";
                } else {
                    auto ct = std::chrono::duration_cast<dur>(t).count();
                    std::cout << s <<" time: "<< ct << " s\n";
                }
            };

            std::cout << "---------------\n";
            std::cout << "Algorithm Stats:\n";
            algo_stats.to_json(std::cout); //TODO text output
            std::cout << "\n";
            std::cout << "---------------\n";
            print_time("startup", setup_duration);
            print_time("compression", comp_duration);
            print_time("teardown", end_duration);
            std::cout << "---------------\n";
        }
    } catch (std::exception& e) {
        std::cout << "Error: " << e.what() << '\n';
        return 1;
    }

    return 0;
}
<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2012 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "registration.h"

#include "python_wrap_vil_smart_ptr.h"

#include <boost/python/class.hpp>
#include <boost/thread/once.hpp>

#include <vil/vil_image_view.h>
#include <vil/vil_image_view_base.h>
#include <vil/vil_memory_chunk.h>

#include <typeinfo>

/**
 * \file numpy/registration.cxx
 *
 * \brief Implementation of functions to register vil types to \c boost::python.
 */

using namespace boost::python;

namespace vistk
{

namespace python
{

static void register_memory_chunk_to_python();

void
register_memory_chunk()
{
  static boost::once_flag once;

  boost::call_once(once, register_memory_chunk_to_python);
}

void
register_memory_chunk_to_python()
{
  // Expose vil_memory_chunk to Python. This is treated as opaque because Python
  // shouldn't be messing with such things, but it allows us to have numpy
  // arrays hold a reference to the memory chunk that is being used when
  // converting a vil_image_view into a NumPy array.
  class_<vil_memory_chunk, vil_memory_chunk_sptr, boost::noncopyable>("_VilMemoryChunk"
    , "<internal>"
    , no_init);
}

static void register_image_base_to_python();

void
register_image_base()
{
  static boost::once_flag once;

  boost::call_once(once, register_image_base_to_python);
}

void
register_image_base_to_python()
{
  class_<vil_image_view_base, vil_image_view_base_sptr, boost::noncopyable>("_VilImage"
    , "<internal>"
    , no_init);
}

template <typename T>
static void register_image_to_python();

template <typename T>
void
register_image_type()
{
  static boost::once_flag once;

  boost::call_once(once, register_image_to_python<T>);
}

template <typename T>
void
register_image_to_python()
{
  std::string base = "_VilImage_";

  base += typeid(T).name();

  class_<vil_image_view<T>, boost::noncopyable>(base.c_str()
    , "<internal>"
    , no_init);
}

}

}

#define REGISTER_IMAGE_TYPE(type) \
  template void vistk::python::register_image_type<type>()

REGISTER_IMAGE_TYPE(bool);
REGISTER_IMAGE_TYPE(signed char);
REGISTER_IMAGE_TYPE(unsigned char);
REGISTER_IMAGE_TYPE(short);
REGISTER_IMAGE_TYPE(unsigned short);
REGISTER_IMAGE_TYPE(int);
REGISTER_IMAGE_TYPE(unsigned int);
REGISTER_IMAGE_TYPE(long);
REGISTER_IMAGE_TYPE(unsigned long);
#if VXL_HAS_INT_64
REGISTER_IMAGE_TYPE(long long);
REGISTER_IMAGE_TYPE(unsigned long long);
#endif
REGISTER_IMAGE_TYPE(float);
REGISTER_IMAGE_TYPE(double);
<commit_msg>Rename the registration instantiation function<commit_after>/*ckwg +5
 * Copyright 2012-2013 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "registration.h"

#include "python_wrap_vil_smart_ptr.h"

#include <boost/python/class.hpp>
#include <boost/thread/once.hpp>

#include <vil/vil_image_view.h>
#include <vil/vil_image_view_base.h>
#include <vil/vil_memory_chunk.h>

#include <typeinfo>

/**
 * \file numpy/registration.cxx
 *
 * \brief Implementation of functions to register vil types to \c boost::python.
 */

using namespace boost::python;

namespace vistk
{

namespace python
{

static void register_memory_chunk_to_python();

void
register_memory_chunk()
{
  static boost::once_flag once;

  boost::call_once(once, register_memory_chunk_to_python);
}

void
register_memory_chunk_to_python()
{
  // Expose vil_memory_chunk to Python. This is treated as opaque because Python
  // shouldn't be messing with such things, but it allows us to have numpy
  // arrays hold a reference to the memory chunk that is being used when
  // converting a vil_image_view into a NumPy array.
  class_<vil_memory_chunk, vil_memory_chunk_sptr, boost::noncopyable>("_VilMemoryChunk"
    , "<internal>"
    , no_init);
}

static void register_image_base_to_python();

void
register_image_base()
{
  static boost::once_flag once;

  boost::call_once(once, register_image_base_to_python);
}

void
register_image_base_to_python()
{
  class_<vil_image_view_base, vil_image_view_base_sptr, boost::noncopyable>("_VilImage"
    , "<internal>"
    , no_init);
}

template <typename T>
static void register_image_to_python();

template <typename T>
void
register_image_type()
{
  static boost::once_flag once;

  boost::call_once(once, register_image_to_python<T>);
}

template <typename T>
void
register_image_to_python()
{
  std::string base = "_VilImage_";

  base += typeid(T).name();

  class_<vil_image_view<T>, boost::noncopyable>(base.c_str()
    , "<internal>"
    , no_init);
}

}

}

#define INSTANTIATE_REGISTER_IMAGE_TYPE(type) \
  template VISTK_PYTHON_NUMPY_EXPORT void vistk::python::register_image_type<type>()

INSTANTIATE_REGISTER_IMAGE_TYPE(bool);
INSTANTIATE_REGISTER_IMAGE_TYPE(signed char);
INSTANTIATE_REGISTER_IMAGE_TYPE(unsigned char);
INSTANTIATE_REGISTER_IMAGE_TYPE(short);
INSTANTIATE_REGISTER_IMAGE_TYPE(unsigned short);
INSTANTIATE_REGISTER_IMAGE_TYPE(int);
INSTANTIATE_REGISTER_IMAGE_TYPE(unsigned int);
INSTANTIATE_REGISTER_IMAGE_TYPE(long);
INSTANTIATE_REGISTER_IMAGE_TYPE(unsigned long);
#if VXL_HAS_INT_64
INSTANTIATE_REGISTER_IMAGE_TYPE(long long);
INSTANTIATE_REGISTER_IMAGE_TYPE(unsigned long long);
#endif
INSTANTIATE_REGISTER_IMAGE_TYPE(float);
INSTANTIATE_REGISTER_IMAGE_TYPE(double);

#undef INSTANTIATE_REGISTER_IMAGE_TYPE
<|endoftext|>