<commit_before>/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 "stack.h"

#include "oat/runtime/context.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "thread_list.h"
#include "throw_location.h"

namespace art {

mirror::Object* ShadowFrame::GetThisObject() const {
  mirror::AbstractMethod* m = GetMethod();
  if (m->IsStatic()) {
    return NULL;
  } else if (m->IsNative()) {
    return GetVRegReference(0);
  } else {
    const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
    CHECK(code_item != NULL) << PrettyMethod(m);
    uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
    return GetVRegReference(reg);
  }
}

mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const {
  mirror::AbstractMethod* m = GetMethod();
  if (m->IsStatic()) {
    return NULL;
  } else {
    return GetVRegReference(number_of_vregs_ - num_ins);
  }
}

ThrowLocation ShadowFrame::GetCurrentLocationForThrow() const {
  return ThrowLocation(GetThisObject(), GetMethod(), GetDexPC());
}

size_t ManagedStack::NumJniShadowFrameReferences() const {
  size_t count = 0;
  for (const ManagedStack* current_fragment = this; current_fragment != NULL;
       current_fragment = current_fragment->GetLink()) {
    for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != NULL;
         current_frame = current_frame->GetLink()) {
      if (current_frame->GetMethod()->IsNative()) {
        // The JNI ShadowFrame only contains references. (For indirect reference.)
        count += current_frame->NumberOfVRegs();
      }
    }
  }
  return count;
}

bool ManagedStack::ShadowFramesContain(mirror::Object** shadow_frame_entry) const {
  for (const ManagedStack* current_fragment = this; current_fragment != NULL;
       current_fragment = current_fragment->GetLink()) {
    for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != NULL;
         current_frame = current_frame->GetLink()) {
      if (current_frame->Contains(shadow_frame_entry)) {
        return true;
      }
    }
  }
  return false;
}

StackVisitor::StackVisitor(Thread* thread, Context* context)
    : thread_(thread), cur_shadow_frame_(NULL),
      cur_quick_frame_(NULL), cur_quick_frame_pc_(0), num_frames_(0), cur_depth_(0),
      context_(context) {
  DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
}

uint32_t StackVisitor::GetDexPc() const {
  if (cur_shadow_frame_ != NULL) {
    return cur_shadow_frame_->GetDexPC();
  } else if (cur_quick_frame_ != NULL) {
    return GetMethod()->ToDexPc(cur_quick_frame_pc_);
  } else {
    return 0;
  }
}

mirror::Object* StackVisitor::GetThisObject() const {
  mirror::AbstractMethod* m = GetMethod();
  if (m->IsStatic()) {
    return NULL;
  } else if (m->IsNative()) {
    if (cur_quick_frame_ != NULL) {
      StackIndirectReferenceTable* sirt =
          reinterpret_cast<StackIndirectReferenceTable*>(
              reinterpret_cast<char*>(cur_quick_frame_) +
              m->GetSirtOffsetInBytes());
      return sirt->GetReference(0);
    } else {
      return cur_shadow_frame_->GetVRegReference(0);
    }
  } else {
    const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
    if (code_item == NULL) {
      UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method"
          << PrettyMethod(m);
      return NULL;
    } else {
      uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
      return reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kReferenceVReg));
    }
  }
}

size_t StackVisitor::GetNativePcOffset() const {
  DCHECK(!IsShadowFrame());
  return GetMethod()->NativePcOffset(cur_quick_frame_pc_);
}

uint32_t StackVisitor::GetVReg(mirror::AbstractMethod* m, uint16_t vreg, VRegKind kind) const {
  if (cur_quick_frame_ != NULL) {
    DCHECK(context_ != NULL); // You can't reliably read registers without a context.
    DCHECK(m == GetMethod());
    const VmapTable vmap_table(m->GetVmapTableRaw());
    uint32_t vmap_offset;
    // TODO: IsInContext stops before spotting floating point registers.
    if (vmap_table.IsInContext(vreg, vmap_offset, kind)) {
      bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
      uint32_t spill_mask = is_float ? m->GetFpSpillMask()
                                     : m->GetCoreSpillMask();
      return GetGPR(vmap_table.ComputeRegister(spill_mask, vmap_offset, kind));
    } else {
      const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
      DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions?
      size_t frame_size = m->GetFrameSizeInBytes();
      return GetVReg(cur_quick_frame_, code_item, m->GetCoreSpillMask(), m->GetFpSpillMask(),
                     frame_size, vreg);
    }
  } else {
    return cur_shadow_frame_->GetVReg(vreg);
  }
}

void StackVisitor::SetVReg(mirror::AbstractMethod* m, uint16_t vreg, uint32_t new_value,
                           VRegKind kind) {
  if (cur_quick_frame_ != NULL) {
    DCHECK(context_ != NULL); // You can't reliably write registers without a context.
    DCHECK(m == GetMethod());
    const VmapTable vmap_table(m->GetVmapTableRaw());
    uint32_t vmap_offset;
    // TODO: IsInContext stops before spotting floating point registers.
    if (vmap_table.IsInContext(vreg, vmap_offset, kind)) {
      bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
      uint32_t spill_mask = is_float ? m->GetFpSpillMask() : m->GetCoreSpillMask();
      const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kReferenceVReg);
      SetGPR(reg, new_value);
    } else {
      const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
      DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions?
      uint32_t core_spills = m->GetCoreSpillMask();
      uint32_t fp_spills = m->GetFpSpillMask();
      size_t frame_size = m->GetFrameSizeInBytes();
      int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
      byte* vreg_addr = reinterpret_cast<byte*>(GetCurrentQuickFrame()) + offset;
      *reinterpret_cast<uint32_t*>(vreg_addr) = new_value;
    }
  } else {
    return cur_shadow_frame_->SetVReg(vreg, new_value);
  }
}

uintptr_t StackVisitor::GetGPR(uint32_t reg) const {
  DCHECK (cur_quick_frame_ != NULL) << "This is a quick frame routine";
  return context_->GetGPR(reg);
}

void StackVisitor::SetGPR(uint32_t reg, uintptr_t value) {
  DCHECK (cur_quick_frame_ != NULL) << "This is a quick frame routine";
  context_->SetGPR(reg, value);
}

uintptr_t StackVisitor::GetReturnPc() const {
  mirror::AbstractMethod** sp = GetCurrentQuickFrame();
  DCHECK(sp != NULL);
  byte* pc_addr = reinterpret_cast<byte*>(sp) + GetMethod()->GetReturnPcOffsetInBytes();
  return *reinterpret_cast<uintptr_t*>(pc_addr);
}

void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) {
  mirror::AbstractMethod** sp = GetCurrentQuickFrame();
  CHECK(sp != NULL);
  byte* pc_addr = reinterpret_cast<byte*>(sp) + GetMethod()->GetReturnPcOffsetInBytes();
  *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
}

size_t StackVisitor::ComputeNumFrames(Thread* thread) {
  struct NumFramesVisitor : public StackVisitor {
    explicit NumFramesVisitor(Thread* thread)
        : StackVisitor(thread, NULL), frames(0) {}

    virtual bool VisitFrame() {
      frames++;
      return true;
    }

    size_t frames;
  };
  NumFramesVisitor visitor(thread);
  visitor.WalkStack(true);
  return visitor.frames;
}

void StackVisitor::DescribeStack(Thread* thread) {
  struct DescribeStackVisitor : public StackVisitor {
    explicit DescribeStackVisitor(Thread* thread)
        : StackVisitor(thread, NULL) {}

    virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
      LOG(INFO) << "Frame Id=" << GetFrameId() << " " << DescribeLocation();
      return true;
    }
  };
  DescribeStackVisitor visitor(thread);
  visitor.WalkStack(true);
}

std::string StackVisitor::DescribeLocation() const {
  std::string result("Visiting method '");
  mirror::AbstractMethod* m = GetMethod();
  if (m == NULL) {
    return "upcall";
  }
  result += PrettyMethod(m);
  result += StringPrintf("' at dex PC 0x%04zx", GetDexPc());
  if (!IsShadowFrame()) {
    result += StringPrintf(" (native PC %p)", reinterpret_cast<void*>(GetCurrentQuickFramePc()));
  }
  return result;
}

instrumentation::InstrumentationStackFrame StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const {
  return thread_->GetInstrumentationStack()->at(depth);
}

void StackVisitor::SanityCheckFrame() const {
#ifndef NDEBUG
  mirror::AbstractMethod* method = GetMethod();
  CHECK(method->GetClass() == mirror::AbstractMethod::GetMethodClass() ||
        method->GetClass() == mirror::AbstractMethod::GetConstructorClass());
  if (cur_quick_frame_ != NULL) {
    method->AssertPcIsWithinCode(cur_quick_frame_pc_);
    // Frame sanity.
    size_t frame_size = method->GetFrameSizeInBytes();
    CHECK_NE(frame_size, 0u);
    CHECK_LT(frame_size, 1024u);
    size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
    CHECK_LT(return_pc_offset, frame_size);
  }
#endif
}

void StackVisitor::WalkStack(bool include_transitions) {
  DCHECK(thread_ == Thread::Current() || thread_->IsSuspended());
  CHECK_EQ(cur_depth_, 0U);
  bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
  uint32_t instrumentation_stack_depth = 0;
  for (const ManagedStack* current_fragment = thread_->GetManagedStack(); current_fragment != NULL;
       current_fragment = current_fragment->GetLink()) {
    cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
    cur_quick_frame_ = current_fragment->GetTopQuickFrame();
    cur_quick_frame_pc_ = current_fragment->GetTopQuickFramePc();
    if (cur_quick_frame_ != NULL) {  // Handle quick stack frames.
      // Can't be both a shadow and a quick fragment.
      DCHECK(current_fragment->GetTopShadowFrame() == NULL);
      mirror::AbstractMethod* method = *cur_quick_frame_;
      while (method != NULL) {
        DCHECK(cur_quick_frame_pc_ != GetInstrumentationExitPc());
        SanityCheckFrame();
        bool should_continue = VisitFrame();
        if (UNLIKELY(!should_continue)) {
          return;
        }
        if (context_ != NULL) {
          context_->FillCalleeSaves(*this);
        }
        size_t frame_size = method->GetFrameSizeInBytes();
        // Compute PC for next stack frame from return PC.
        size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
        byte* return_pc_addr = reinterpret_cast<byte*>(cur_quick_frame_) + return_pc_offset;
        uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
        if (UNLIKELY(exit_stubs_installed)) {
          // While profiling, the return pc is restored from the side stack, except when walking
          // the stack for an exception where the side stack will be unwound in VisitFrame.
          if (GetInstrumentationExitPc() == return_pc) {
            instrumentation::InstrumentationStackFrame instrumentation_frame =
                GetInstrumentationStackFrame(instrumentation_stack_depth);
            instrumentation_stack_depth++;
            if (instrumentation_frame.method_ != GetMethod()) {
              LOG(FATAL)  << "Expected: " << PrettyMethod(instrumentation_frame.method_)
                << " Found: " << PrettyMethod(GetMethod());
            }
            if (num_frames_ != 0) {
              // Check agreement of frame Ids only if num_frames_ is computed to avoid infinite
              // recursion.
              CHECK(instrumentation_frame.frame_id_ == GetFrameId())
                    << "Expected: " << instrumentation_frame.frame_id_
                    << " Found: " << GetFrameId();
            }
            return_pc = instrumentation_frame.return_pc_;
          }
        }
        cur_quick_frame_pc_ = return_pc;
        byte* next_frame = reinterpret_cast<byte*>(cur_quick_frame_) + frame_size;
        cur_quick_frame_ = reinterpret_cast<mirror::AbstractMethod**>(next_frame);
        cur_depth_++;
        method = *cur_quick_frame_;
      }
    } else if (cur_shadow_frame_ != NULL) {
      do {
        SanityCheckFrame();
        bool should_continue = VisitFrame();
        if (UNLIKELY(!should_continue)) {
          return;
        }
        cur_depth_++;
        cur_shadow_frame_ = cur_shadow_frame_->GetLink();
      } while(cur_shadow_frame_ != NULL);
    }
    if (include_transitions) {
      bool should_continue = VisitFrame();
      if (!should_continue) {
        return;
      }
    }
    cur_depth_++;
  }
  if (num_frames_ != 0) {
    CHECK_EQ(cur_depth_, num_frames_);
  }
}

}  // namespace art
<commit_msg>Fix portable build shadow frame.<commit_after>/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 "stack.h"

#include "oat/runtime/context.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "thread_list.h"
#include "throw_location.h"

namespace art {

mirror::Object* ShadowFrame::GetThisObject() const {
  mirror::AbstractMethod* m = GetMethod();
  if (m->IsStatic()) {
    return NULL;
  } else if (m->IsNative()) {
    return GetVRegReference(0);
  } else {
    const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
    CHECK(code_item != NULL) << PrettyMethod(m);
    uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
    return GetVRegReference(reg);
  }
}

mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const {
  mirror::AbstractMethod* m = GetMethod();
  if (m->IsStatic()) {
    return NULL;
  } else {
    return GetVRegReference(NumberOfVRegs() - num_ins);
  }
}

ThrowLocation ShadowFrame::GetCurrentLocationForThrow() const {
  return ThrowLocation(GetThisObject(), GetMethod(), GetDexPC());
}

size_t ManagedStack::NumJniShadowFrameReferences() const {
  size_t count = 0;
  for (const ManagedStack* current_fragment = this; current_fragment != NULL;
       current_fragment = current_fragment->GetLink()) {
    for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != NULL;
         current_frame = current_frame->GetLink()) {
      if (current_frame->GetMethod()->IsNative()) {
        // The JNI ShadowFrame only contains references. (For indirect reference.)
        count += current_frame->NumberOfVRegs();
      }
    }
  }
  return count;
}

bool ManagedStack::ShadowFramesContain(mirror::Object** shadow_frame_entry) const {
  for (const ManagedStack* current_fragment = this; current_fragment != NULL;
       current_fragment = current_fragment->GetLink()) {
    for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != NULL;
         current_frame = current_frame->GetLink()) {
      if (current_frame->Contains(shadow_frame_entry)) {
        return true;
      }
    }
  }
  return false;
}

StackVisitor::StackVisitor(Thread* thread, Context* context)
    : thread_(thread), cur_shadow_frame_(NULL),
      cur_quick_frame_(NULL), cur_quick_frame_pc_(0), num_frames_(0), cur_depth_(0),
      context_(context) {
  DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
}

uint32_t StackVisitor::GetDexPc() const {
  if (cur_shadow_frame_ != NULL) {
    return cur_shadow_frame_->GetDexPC();
  } else if (cur_quick_frame_ != NULL) {
    return GetMethod()->ToDexPc(cur_quick_frame_pc_);
  } else {
    return 0;
  }
}

mirror::Object* StackVisitor::GetThisObject() const {
  mirror::AbstractMethod* m = GetMethod();
  if (m->IsStatic()) {
    return NULL;
  } else if (m->IsNative()) {
    if (cur_quick_frame_ != NULL) {
      StackIndirectReferenceTable* sirt =
          reinterpret_cast<StackIndirectReferenceTable*>(
              reinterpret_cast<char*>(cur_quick_frame_) +
              m->GetSirtOffsetInBytes());
      return sirt->GetReference(0);
    } else {
      return cur_shadow_frame_->GetVRegReference(0);
    }
  } else {
    const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
    if (code_item == NULL) {
      UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method"
          << PrettyMethod(m);
      return NULL;
    } else {
      uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
      return reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kReferenceVReg));
    }
  }
}

size_t StackVisitor::GetNativePcOffset() const {
  DCHECK(!IsShadowFrame());
  return GetMethod()->NativePcOffset(cur_quick_frame_pc_);
}

uint32_t StackVisitor::GetVReg(mirror::AbstractMethod* m, uint16_t vreg, VRegKind kind) const {
  if (cur_quick_frame_ != NULL) {
    DCHECK(context_ != NULL); // You can't reliably read registers without a context.
    DCHECK(m == GetMethod());
    const VmapTable vmap_table(m->GetVmapTableRaw());
    uint32_t vmap_offset;
    // TODO: IsInContext stops before spotting floating point registers.
    if (vmap_table.IsInContext(vreg, vmap_offset, kind)) {
      bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
      uint32_t spill_mask = is_float ? m->GetFpSpillMask()
                                     : m->GetCoreSpillMask();
      return GetGPR(vmap_table.ComputeRegister(spill_mask, vmap_offset, kind));
    } else {
      const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
      DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions?
      size_t frame_size = m->GetFrameSizeInBytes();
      return GetVReg(cur_quick_frame_, code_item, m->GetCoreSpillMask(), m->GetFpSpillMask(),
                     frame_size, vreg);
    }
  } else {
    return cur_shadow_frame_->GetVReg(vreg);
  }
}

void StackVisitor::SetVReg(mirror::AbstractMethod* m, uint16_t vreg, uint32_t new_value,
                           VRegKind kind) {
  if (cur_quick_frame_ != NULL) {
    DCHECK(context_ != NULL); // You can't reliably write registers without a context.
    DCHECK(m == GetMethod());
    const VmapTable vmap_table(m->GetVmapTableRaw());
    uint32_t vmap_offset;
    // TODO: IsInContext stops before spotting floating point registers.
    if (vmap_table.IsInContext(vreg, vmap_offset, kind)) {
      bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
      uint32_t spill_mask = is_float ? m->GetFpSpillMask() : m->GetCoreSpillMask();
      const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kReferenceVReg);
      SetGPR(reg, new_value);
    } else {
      const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
      DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions?
      uint32_t core_spills = m->GetCoreSpillMask();
      uint32_t fp_spills = m->GetFpSpillMask();
      size_t frame_size = m->GetFrameSizeInBytes();
      int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
      byte* vreg_addr = reinterpret_cast<byte*>(GetCurrentQuickFrame()) + offset;
      *reinterpret_cast<uint32_t*>(vreg_addr) = new_value;
    }
  } else {
    return cur_shadow_frame_->SetVReg(vreg, new_value);
  }
}

uintptr_t StackVisitor::GetGPR(uint32_t reg) const {
  DCHECK (cur_quick_frame_ != NULL) << "This is a quick frame routine";
  return context_->GetGPR(reg);
}

void StackVisitor::SetGPR(uint32_t reg, uintptr_t value) {
  DCHECK (cur_quick_frame_ != NULL) << "This is a quick frame routine";
  context_->SetGPR(reg, value);
}

uintptr_t StackVisitor::GetReturnPc() const {
  mirror::AbstractMethod** sp = GetCurrentQuickFrame();
  DCHECK(sp != NULL);
  byte* pc_addr = reinterpret_cast<byte*>(sp) + GetMethod()->GetReturnPcOffsetInBytes();
  return *reinterpret_cast<uintptr_t*>(pc_addr);
}

void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) {
  mirror::AbstractMethod** sp = GetCurrentQuickFrame();
  CHECK(sp != NULL);
  byte* pc_addr = reinterpret_cast<byte*>(sp) + GetMethod()->GetReturnPcOffsetInBytes();
  *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
}

size_t StackVisitor::ComputeNumFrames(Thread* thread) {
  struct NumFramesVisitor : public StackVisitor {
    explicit NumFramesVisitor(Thread* thread)
        : StackVisitor(thread, NULL), frames(0) {}

    virtual bool VisitFrame() {
      frames++;
      return true;
    }

    size_t frames;
  };
  NumFramesVisitor visitor(thread);
  visitor.WalkStack(true);
  return visitor.frames;
}

void StackVisitor::DescribeStack(Thread* thread) {
  struct DescribeStackVisitor : public StackVisitor {
    explicit DescribeStackVisitor(Thread* thread)
        : StackVisitor(thread, NULL) {}

    virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
      LOG(INFO) << "Frame Id=" << GetFrameId() << " " << DescribeLocation();
      return true;
    }
  };
  DescribeStackVisitor visitor(thread);
  visitor.WalkStack(true);
}

std::string StackVisitor::DescribeLocation() const {
  std::string result("Visiting method '");
  mirror::AbstractMethod* m = GetMethod();
  if (m == NULL) {
    return "upcall";
  }
  result += PrettyMethod(m);
  result += StringPrintf("' at dex PC 0x%04zx", GetDexPc());
  if (!IsShadowFrame()) {
    result += StringPrintf(" (native PC %p)", reinterpret_cast<void*>(GetCurrentQuickFramePc()));
  }
  return result;
}

instrumentation::InstrumentationStackFrame StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const {
  return thread_->GetInstrumentationStack()->at(depth);
}

void StackVisitor::SanityCheckFrame() const {
#ifndef NDEBUG
  mirror::AbstractMethod* method = GetMethod();
  CHECK(method->GetClass() == mirror::AbstractMethod::GetMethodClass() ||
        method->GetClass() == mirror::AbstractMethod::GetConstructorClass());
  if (cur_quick_frame_ != NULL) {
    method->AssertPcIsWithinCode(cur_quick_frame_pc_);
    // Frame sanity.
    size_t frame_size = method->GetFrameSizeInBytes();
    CHECK_NE(frame_size, 0u);
    CHECK_LT(frame_size, 1024u);
    size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
    CHECK_LT(return_pc_offset, frame_size);
  }
#endif
}

void StackVisitor::WalkStack(bool include_transitions) {
  DCHECK(thread_ == Thread::Current() || thread_->IsSuspended());
  CHECK_EQ(cur_depth_, 0U);
  bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
  uint32_t instrumentation_stack_depth = 0;
  for (const ManagedStack* current_fragment = thread_->GetManagedStack(); current_fragment != NULL;
       current_fragment = current_fragment->GetLink()) {
    cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
    cur_quick_frame_ = current_fragment->GetTopQuickFrame();
    cur_quick_frame_pc_ = current_fragment->GetTopQuickFramePc();
    if (cur_quick_frame_ != NULL) {  // Handle quick stack frames.
      // Can't be both a shadow and a quick fragment.
      DCHECK(current_fragment->GetTopShadowFrame() == NULL);
      mirror::AbstractMethod* method = *cur_quick_frame_;
      while (method != NULL) {
        DCHECK(cur_quick_frame_pc_ != GetInstrumentationExitPc());
        SanityCheckFrame();
        bool should_continue = VisitFrame();
        if (UNLIKELY(!should_continue)) {
          return;
        }
        if (context_ != NULL) {
          context_->FillCalleeSaves(*this);
        }
        size_t frame_size = method->GetFrameSizeInBytes();
        // Compute PC for next stack frame from return PC.
        size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
        byte* return_pc_addr = reinterpret_cast<byte*>(cur_quick_frame_) + return_pc_offset;
        uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
        if (UNLIKELY(exit_stubs_installed)) {
          // While profiling, the return pc is restored from the side stack, except when walking
          // the stack for an exception where the side stack will be unwound in VisitFrame.
          if (GetInstrumentationExitPc() == return_pc) {
            instrumentation::InstrumentationStackFrame instrumentation_frame =
                GetInstrumentationStackFrame(instrumentation_stack_depth);
            instrumentation_stack_depth++;
            if (instrumentation_frame.method_ != GetMethod()) {
              LOG(FATAL)  << "Expected: " << PrettyMethod(instrumentation_frame.method_)
                << " Found: " << PrettyMethod(GetMethod());
            }
            if (num_frames_ != 0) {
              // Check agreement of frame Ids only if num_frames_ is computed to avoid infinite
              // recursion.
              CHECK(instrumentation_frame.frame_id_ == GetFrameId())
                    << "Expected: " << instrumentation_frame.frame_id_
                    << " Found: " << GetFrameId();
            }
            return_pc = instrumentation_frame.return_pc_;
          }
        }
        cur_quick_frame_pc_ = return_pc;
        byte* next_frame = reinterpret_cast<byte*>(cur_quick_frame_) + frame_size;
        cur_quick_frame_ = reinterpret_cast<mirror::AbstractMethod**>(next_frame);
        cur_depth_++;
        method = *cur_quick_frame_;
      }
    } else if (cur_shadow_frame_ != NULL) {
      do {
        SanityCheckFrame();
        bool should_continue = VisitFrame();
        if (UNLIKELY(!should_continue)) {
          return;
        }
        cur_depth_++;
        cur_shadow_frame_ = cur_shadow_frame_->GetLink();
      } while(cur_shadow_frame_ != NULL);
    }
    if (include_transitions) {
      bool should_continue = VisitFrame();
      if (!should_continue) {
        return;
      }
    }
    cur_depth_++;
  }
  if (num_frames_ != 0) {
    CHECK_EQ(cur_depth_, num_frames_);
  }
}

}  // namespace art
<|endoftext|>


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

#include "state.h"

#include <assert.h>
#include <stdio.h>

#include "edit_distance.h"
#include "graph.h"
#include "metrics.h"
#include "util.h"

void Pool::EdgeScheduled(const Edge& edge) {
  if (depth_ != 0)
    current_use_ += edge.weight();
}

void Pool::EdgeFinished(const Edge& edge) {
  if (depth_ != 0)
    current_use_ -= edge.weight();
}

void Pool::DelayEdge(Edge* edge) {
  assert(depth_ != 0);
  delayed_.insert(edge);
}

void Pool::RetrieveReadyEdges(set<Edge*>* ready_queue) {
  DelayedEdges::iterator it = delayed_.begin();
  while (it != delayed_.end()) {
    Edge* edge = *it;
    if (current_use_ + edge->weight() > depth_)
      break;
    ready_queue->insert(edge);
    EdgeScheduled(*edge);
    ++it;
  }
  delayed_.erase(delayed_.begin(), it);
}

void Pool::Dump() const {
  printf("%s (%d/%d) ->\n", name_.c_str(), current_use_, depth_);
  for (DelayedEdges::const_iterator it = delayed_.begin();
       it != delayed_.end(); ++it)
  {
    printf("\t");
    (*it)->Dump();
  }
}

bool Pool::WeightedEdgeCmp(const Edge* a, const Edge* b) {
  if (!a) return b;
  if (!b) return false;
  int weight_diff = a->weight() - b->weight();
  return ((weight_diff < 0) || (weight_diff == 0 && a < b));
}

Pool State::kDefaultPool("", 0);
const Rule State::kPhonyRule("phony");

State::State() {
  AddRule(&kPhonyRule);
  AddPool(&kDefaultPool);
}

void State::AddRule(const Rule* rule) {
  assert(LookupRule(rule->name()) == NULL);
  rules_[rule->name()] = rule;
}

const Rule* State::LookupRule(const string& rule_name) {
  map<string, const Rule*>::iterator i = rules_.find(rule_name);
  if (i == rules_.end())
    return NULL;
  return i->second;
}

void State::AddPool(Pool* pool) {
  assert(LookupPool(pool->name()) == NULL);
  pools_[pool->name()] = pool;
}

Pool* State::LookupPool(const string& pool_name) {
  map<string, Pool*>::iterator i = pools_.find(pool_name);
  if (i == pools_.end())
    return NULL;
  return i->second;
}

Edge* State::AddEdge(const Rule* rule) {
  Edge* edge = new Edge();
  edge->rule_ = rule;
  edge->pool_ = &State::kDefaultPool;
  edge->env_ = &bindings_;
  edges_.push_back(edge);
  return edge;
}

Node* State::GetNode(StringPiece path) {
  Node* node = LookupNode(path);
  if (node)
    return node;
  node = new Node(path.AsString());
  paths_[node->path()] = node;
  return node;
}

Node* State::LookupNode(StringPiece path) {
  METRIC_RECORD("lookup node");
  Paths::iterator i = paths_.find(path);
  if (i != paths_.end())
    return i->second;
  return NULL;
}

Node* State::SpellcheckNode(const string& path) {
  const bool kAllowReplacements = true;
  const int kMaxValidEditDistance = 3;

  int min_distance = kMaxValidEditDistance + 1;
  Node* result = NULL;
  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
    int distance = EditDistance(
        i->first, path, kAllowReplacements, kMaxValidEditDistance);
    if (distance < min_distance && i->second) {
      min_distance = distance;
      result = i->second;
    }
  }
  return result;
}

void State::AddIn(Edge* edge, StringPiece path) {
  Node* node = GetNode(path);
  edge->inputs_.push_back(node);
  node->AddOutEdge(edge);
}

void State::AddOut(Edge* edge, StringPiece path) {
  Node* node = GetNode(path);
  edge->outputs_.push_back(node);
  if (node->in_edge()) {
    Warning("multiple rules generate %s. "
            "build will not be correct; continuing anyway",
            path.AsString().c_str());
  }
  node->set_in_edge(edge);
}

bool State::AddDefault(StringPiece path, string* err) {
  Node* node = LookupNode(path);
  if (!node) {
    *err = "unknown target '" + path.AsString() + "'";
    return false;
  }
  defaults_.push_back(node);
  return true;
}

vector<Node*> State::RootNodes(string* err) {
  vector<Node*> root_nodes;
  // Search for nodes with no output.
  for (vector<Edge*>::iterator e = edges_.begin(); e != edges_.end(); ++e) {
    for (vector<Node*>::iterator out = (*e)->outputs_.begin();
         out != (*e)->outputs_.end(); ++out) {
      if ((*out)->out_edges().empty())
        root_nodes.push_back(*out);
    }
  }

  if (!edges_.empty() && root_nodes.empty())
    *err = "could not determine root nodes of build graph";

  assert(edges_.empty() || !root_nodes.empty());
  return root_nodes;
}

vector<Node*> State::DefaultNodes(string* err) {
  return defaults_.empty() ? RootNodes(err) : defaults_;
}

void State::Reset() {
  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i)
    i->second->ResetState();
  for (vector<Edge*>::iterator e = edges_.begin(); e != edges_.end(); ++e)
    (*e)->outputs_ready_ = false;
}

void State::Dump() {
  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
    Node* node = i->second;
    printf("%s %s [id:%d]\n",
           node->path().c_str(),
           node->status_known() ? (node->dirty() ? "dirty" : "clean")
                                : "unknown",
           node->id());
  }
  if (!pools_.empty()) {
    printf("resource_pools:\n");
    for (map<string, Pool*>::const_iterator it = pools_.begin();
         it != pools_.end(); ++it)
    {
      if (!it->second->name().empty()) {
        it->second->Dump();
      }
    }
  }
}
<commit_msg>adjust the wording in "multiple rules generate X" warning<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "state.h"

#include <assert.h>
#include <stdio.h>

#include "edit_distance.h"
#include "graph.h"
#include "metrics.h"
#include "util.h"

void Pool::EdgeScheduled(const Edge& edge) {
  if (depth_ != 0)
    current_use_ += edge.weight();
}

void Pool::EdgeFinished(const Edge& edge) {
  if (depth_ != 0)
    current_use_ -= edge.weight();
}

void Pool::DelayEdge(Edge* edge) {
  assert(depth_ != 0);
  delayed_.insert(edge);
}

void Pool::RetrieveReadyEdges(set<Edge*>* ready_queue) {
  DelayedEdges::iterator it = delayed_.begin();
  while (it != delayed_.end()) {
    Edge* edge = *it;
    if (current_use_ + edge->weight() > depth_)
      break;
    ready_queue->insert(edge);
    EdgeScheduled(*edge);
    ++it;
  }
  delayed_.erase(delayed_.begin(), it);
}

void Pool::Dump() const {
  printf("%s (%d/%d) ->\n", name_.c_str(), current_use_, depth_);
  for (DelayedEdges::const_iterator it = delayed_.begin();
       it != delayed_.end(); ++it)
  {
    printf("\t");
    (*it)->Dump();
  }
}

bool Pool::WeightedEdgeCmp(const Edge* a, const Edge* b) {
  if (!a) return b;
  if (!b) return false;
  int weight_diff = a->weight() - b->weight();
  return ((weight_diff < 0) || (weight_diff == 0 && a < b));
}

Pool State::kDefaultPool("", 0);
const Rule State::kPhonyRule("phony");

State::State() {
  AddRule(&kPhonyRule);
  AddPool(&kDefaultPool);
}

void State::AddRule(const Rule* rule) {
  assert(LookupRule(rule->name()) == NULL);
  rules_[rule->name()] = rule;
}

const Rule* State::LookupRule(const string& rule_name) {
  map<string, const Rule*>::iterator i = rules_.find(rule_name);
  if (i == rules_.end())
    return NULL;
  return i->second;
}

void State::AddPool(Pool* pool) {
  assert(LookupPool(pool->name()) == NULL);
  pools_[pool->name()] = pool;
}

Pool* State::LookupPool(const string& pool_name) {
  map<string, Pool*>::iterator i = pools_.find(pool_name);
  if (i == pools_.end())
    return NULL;
  return i->second;
}

Edge* State::AddEdge(const Rule* rule) {
  Edge* edge = new Edge();
  edge->rule_ = rule;
  edge->pool_ = &State::kDefaultPool;
  edge->env_ = &bindings_;
  edges_.push_back(edge);
  return edge;
}

Node* State::GetNode(StringPiece path) {
  Node* node = LookupNode(path);
  if (node)
    return node;
  node = new Node(path.AsString());
  paths_[node->path()] = node;
  return node;
}

Node* State::LookupNode(StringPiece path) {
  METRIC_RECORD("lookup node");
  Paths::iterator i = paths_.find(path);
  if (i != paths_.end())
    return i->second;
  return NULL;
}

Node* State::SpellcheckNode(const string& path) {
  const bool kAllowReplacements = true;
  const int kMaxValidEditDistance = 3;

  int min_distance = kMaxValidEditDistance + 1;
  Node* result = NULL;
  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
    int distance = EditDistance(
        i->first, path, kAllowReplacements, kMaxValidEditDistance);
    if (distance < min_distance && i->second) {
      min_distance = distance;
      result = i->second;
    }
  }
  return result;
}

void State::AddIn(Edge* edge, StringPiece path) {
  Node* node = GetNode(path);
  edge->inputs_.push_back(node);
  node->AddOutEdge(edge);
}

void State::AddOut(Edge* edge, StringPiece path) {
  Node* node = GetNode(path);
  edge->outputs_.push_back(node);
  if (node->in_edge()) {
    Warning("multiple rules generate %s. "
            "builds involving this target will not be correct; "
            "continuing anyway",
            path.AsString().c_str());
  }
  node->set_in_edge(edge);
}

bool State::AddDefault(StringPiece path, string* err) {
  Node* node = LookupNode(path);
  if (!node) {
    *err = "unknown target '" + path.AsString() + "'";
    return false;
  }
  defaults_.push_back(node);
  return true;
}

vector<Node*> State::RootNodes(string* err) {
  vector<Node*> root_nodes;
  // Search for nodes with no output.
  for (vector<Edge*>::iterator e = edges_.begin(); e != edges_.end(); ++e) {
    for (vector<Node*>::iterator out = (*e)->outputs_.begin();
         out != (*e)->outputs_.end(); ++out) {
      if ((*out)->out_edges().empty())
        root_nodes.push_back(*out);
    }
  }

  if (!edges_.empty() && root_nodes.empty())
    *err = "could not determine root nodes of build graph";

  assert(edges_.empty() || !root_nodes.empty());
  return root_nodes;
}

vector<Node*> State::DefaultNodes(string* err) {
  return defaults_.empty() ? RootNodes(err) : defaults_;
}

void State::Reset() {
  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i)
    i->second->ResetState();
  for (vector<Edge*>::iterator e = edges_.begin(); e != edges_.end(); ++e)
    (*e)->outputs_ready_ = false;
}

void State::Dump() {
  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
    Node* node = i->second;
    printf("%s %s [id:%d]\n",
           node->path().c_str(),
           node->status_known() ? (node->dirty() ? "dirty" : "clean")
                                : "unknown",
           node->id());
  }
  if (!pools_.empty()) {
    printf("resource_pools:\n");
    for (map<string, Pool*>::const_iterator it = pools_.begin();
         it != pools_.end(); ++it)
    {
      if (!it->second->name().empty()) {
        it->second->Dump();
      }
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#include <sync.h>
#include <tinyformat.h>

#include <logging.h>
#include <util/strencodings.h>
#include <util/threadnames.h>

#include <stdio.h>

#include <map>
#include <memory>
#include <set>

#ifdef DEBUG_LOCKCONTENTION
#if !defined(HAVE_THREAD_LOCAL)
static_assert(false, "thread_local is not supported");
#endif
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s Locker: %s:%d\n", pszName, pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks A, then B, then C
//    Thread 2 locks D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation {
    CLockLocation(
        const char* pszName,
        const char* pszFile,
        int nLine,
        bool fTryIn,
        const std::string& thread_name)
        : fTry(fTryIn),
          mutexName(pszName),
          sourceFile(pszFile),
          m_thread_name(thread_name),
          sourceLine(nLine) {}

    std::string ToString() const
    {
        return tfm::format(
            "%s %s:%s%s (in thread %s)",
            mutexName, sourceFile, itostr(sourceLine), (fTry ? " (TRY)" : ""), m_thread_name);
    }

private:
    bool fTry;
    std::string mutexName;
    std::string sourceFile;
    const std::string& m_thread_name;
    int sourceLine;
};

typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
typedef std::set<std::pair<void*, void*> > InvLockOrders;

struct LockData {
    // Very ugly hack: as the global constructs and destructors run single
    // threaded, we use this boolean to know whether LockData still exists,
    // as DeleteLock can get called by global CCriticalSection destructors
    // after LockData disappears.
    bool available;
    LockData() : available(true) {}
    ~LockData() { available = false; }

    LockOrders lockorders;
    InvLockOrders invlockorders;
    std::mutex dd_mutex;
};
LockData& GetLockData() {
    static LockData lockdata;
    return lockdata;
}

static thread_local LockStack g_lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    std::string strOutput = "";
    strOutput += "POTENTIAL DEADLOCK DETECTED\n";
    strOutput += "Previous lock order was:\n";
    for (const std::pair<void*, CLockLocation> & i : s2) {
        if (i.first == mismatch.first) {
            strOutput += " (1)";
        }
        if (i.first == mismatch.second) {
            strOutput += " (2)";
        }
        strOutput += strprintf(" %s\n", i.second.ToString().c_str());
    }
    strOutput += "Current lock order is:\n";
    for (const std::pair<void*, CLockLocation> & i : s1) {
        if (i.first == mismatch.first) {
            strOutput += " (1)";
        }
        if (i.first == mismatch.second) {
            strOutput += " (2)";
        }
        strOutput += strprintf(" %s\n", i.second.ToString().c_str());
    }

    printf("%s\n", strOutput.c_str());
    LogPrintf("%s\n", strOutput.c_str());

    if (g_debug_lockorder_abort) {
        fprintf(stderr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__);
        abort();
    }
    throw std::logic_error("potential deadlock detected");
}

static void push_lock(void* c, const CLockLocation& locklocation)
{
    LockData& lockdata = GetLockData();
    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);

    g_lockstack.push_back(std::make_pair(c, locklocation));

    for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
        if (i.first == c)
            break;

        std::pair<void*, void*> p1 = std::make_pair(i.first, c);
        if (lockdata.lockorders.count(p1))
            continue;
        lockdata.lockorders.emplace(p1, g_lockstack);

        std::pair<void*, void*> p2 = std::make_pair(c, i.first);
        lockdata.invlockorders.insert(p2);
        if (lockdata.lockorders.count(p2))
            potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
    }
}

static void pop_lock()
{
    g_lockstack.pop_back();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName()));
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    for (const std::pair<void*, CLockLocation>& i : g_lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

template <typename MutexType>
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs)
{
    for (const std::pair<void*, CLockLocation>& i : g_lockstack)
        if (i.first == cs)
            return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
    abort();
}
template void AssertLockHeldInternal(const char*, const char*, int, Mutex*);
template void AssertLockHeldInternal(const char*, const char*, int, CCriticalSection*);

void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
    for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
        if (i.first == cs) {
            fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
            abort();
        }
    }
}

void DeleteLock(void* cs)
{
    LockData& lockdata = GetLockData();
    if (!lockdata.available) {
        // We're already shutting down.
        return;
    }
    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
    std::pair<void*, void*> item = std::make_pair(cs, nullptr);
    LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
    while (it != lockdata.lockorders.end() && it->first.first == cs) {
        std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
        lockdata.invlockorders.erase(invitem);
        lockdata.lockorders.erase(it++);
    }
    InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
    while (invit != lockdata.invlockorders.end() && invit->first == cs) {
        std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
        lockdata.lockorders.erase(invinvitem);
        lockdata.invlockorders.erase(invit++);
    }
}

bool g_debug_lockorder_abort = true;

#endif /* DEBUG_LOCKORDER */
<commit_msg>bitcoin-config.h -> dash-config.h<commit_after>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/dash-config.h>
#endif

#include <sync.h>
#include <tinyformat.h>

#include <logging.h>
#include <util/strencodings.h>
#include <util/threadnames.h>

#include <stdio.h>

#include <map>
#include <memory>
#include <set>

#ifdef DEBUG_LOCKCONTENTION
#if !defined(HAVE_THREAD_LOCAL)
static_assert(false, "thread_local is not supported");
#endif
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s Locker: %s:%d\n", pszName, pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks A, then B, then C
//    Thread 2 locks D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation {
    CLockLocation(
        const char* pszName,
        const char* pszFile,
        int nLine,
        bool fTryIn,
        const std::string& thread_name)
        : fTry(fTryIn),
          mutexName(pszName),
          sourceFile(pszFile),
          m_thread_name(thread_name),
          sourceLine(nLine) {}

    std::string ToString() const
    {
        return tfm::format(
            "%s %s:%s%s (in thread %s)",
            mutexName, sourceFile, itostr(sourceLine), (fTry ? " (TRY)" : ""), m_thread_name);
    }

private:
    bool fTry;
    std::string mutexName;
    std::string sourceFile;
    const std::string& m_thread_name;
    int sourceLine;
};

typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
typedef std::set<std::pair<void*, void*> > InvLockOrders;

struct LockData {
    // Very ugly hack: as the global constructs and destructors run single
    // threaded, we use this boolean to know whether LockData still exists,
    // as DeleteLock can get called by global CCriticalSection destructors
    // after LockData disappears.
    bool available;
    LockData() : available(true) {}
    ~LockData() { available = false; }

    LockOrders lockorders;
    InvLockOrders invlockorders;
    std::mutex dd_mutex;
};
LockData& GetLockData() {
    static LockData lockdata;
    return lockdata;
}

static thread_local LockStack g_lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    std::string strOutput = "";
    strOutput += "POTENTIAL DEADLOCK DETECTED\n";
    strOutput += "Previous lock order was:\n";
    for (const std::pair<void*, CLockLocation> & i : s2) {
        if (i.first == mismatch.first) {
            strOutput += " (1)";
        }
        if (i.first == mismatch.second) {
            strOutput += " (2)";
        }
        strOutput += strprintf(" %s\n", i.second.ToString().c_str());
    }
    strOutput += "Current lock order is:\n";
    for (const std::pair<void*, CLockLocation> & i : s1) {
        if (i.first == mismatch.first) {
            strOutput += " (1)";
        }
        if (i.first == mismatch.second) {
            strOutput += " (2)";
        }
        strOutput += strprintf(" %s\n", i.second.ToString().c_str());
    }

    printf("%s\n", strOutput.c_str());
    LogPrintf("%s\n", strOutput.c_str());

    if (g_debug_lockorder_abort) {
        fprintf(stderr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__);
        abort();
    }
    throw std::logic_error("potential deadlock detected");
}

static void push_lock(void* c, const CLockLocation& locklocation)
{
    LockData& lockdata = GetLockData();
    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);

    g_lockstack.push_back(std::make_pair(c, locklocation));

    for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
        if (i.first == c)
            break;

        std::pair<void*, void*> p1 = std::make_pair(i.first, c);
        if (lockdata.lockorders.count(p1))
            continue;
        lockdata.lockorders.emplace(p1, g_lockstack);

        std::pair<void*, void*> p2 = std::make_pair(c, i.first);
        lockdata.invlockorders.insert(p2);
        if (lockdata.lockorders.count(p2))
            potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
    }
}

static void pop_lock()
{
    g_lockstack.pop_back();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName()));
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    for (const std::pair<void*, CLockLocation>& i : g_lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

template <typename MutexType>
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs)
{
    for (const std::pair<void*, CLockLocation>& i : g_lockstack)
        if (i.first == cs)
            return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
    abort();
}
template void AssertLockHeldInternal(const char*, const char*, int, Mutex*);
template void AssertLockHeldInternal(const char*, const char*, int, CCriticalSection*);

void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
    for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
        if (i.first == cs) {
            fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
            abort();
        }
    }
}

void DeleteLock(void* cs)
{
    LockData& lockdata = GetLockData();
    if (!lockdata.available) {
        // We're already shutting down.
        return;
    }
    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
    std::pair<void*, void*> item = std::make_pair(cs, nullptr);
    LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
    while (it != lockdata.lockorders.end() && it->first.first == cs) {
        std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
        lockdata.invlockorders.erase(invitem);
        lockdata.lockorders.erase(it++);
    }
    InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
    while (invit != lockdata.invlockorders.end() && invit->first == cs) {
        std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
        lockdata.lockorders.erase(invinvitem);
        lockdata.invlockorders.erase(invit++);
    }
}

bool g_debug_lockorder_abort = true;

#endif /* DEBUG_LOCKORDER */
<|endoftext|>


<commit_before>#include<iostream>
#include <sqlite_modern_cpp.h>
using namespace  sqlite;
using namespace std;

int main() {

	try {
		// creates a database file 'dbfile.db' if it does not exists.
		database db("dbfile.db");

		// executes the query and creates a 'user' table
		db <<
			"create table if not exists user ("
			"   _id integer primary key autoincrement not null,"
			"   age int,"
			"   name text,"
			"   weight real"
			");";

		// inserts a new user record.
		// binds the fields to '?' .
		// note that only types allowed for bindings are :
		//      int ,long, long long, float, double
		//      string , u16string
		// sqlite3 only supports utf8 and utf16 strings, you should use std::string for utf8 and std::u16string for utf16.
		// note that u"my text" is a utf16 string literal of type char16_t * .
		db << "insert into user (age,name,weight) values (?,?,?);"
			<< 20
			<< u"bob"
			<< 83.25;

		int age = 21;
		float weight = 68.5;
		string name = "jack";
		db << u"insert into user (age,name,weight) values (?,?,?);" // utf16 query string
			<< age
			<< name
			<< weight;

		cout << "The new record got assigned id " << db.last_insert_rowid() << endl;

		// slects from user table on a condition ( age > 18 ) and executes
		// the lambda for each row returned .
		db << "select age,name,weight from user where age > ? ;"
			<< 18
			>> [&](int age, string name, double weight) {
			cout << age << ' ' << name << ' ' << weight << endl;
		};

		// selects the count(*) from user table
		// note that you can extract a single culumn single row result only to : int,long,long,float,double,string,u16string
		int count = 0;
		db << "select count(*) from user" >> count;
		cout << "cout : " << count << endl;

		// you can also extract multiple column rows
		db << "select age, name from user where _id=1;" >> tie(age, name);
		cout << "Age = " << age << ", name = " << name << endl;

		// this also works and the returned value will be automatically converted to string
		string str_count;
		db << "select count(*) from user" >> str_count;
		cout << "scount : " << str_count << endl;
	}
	catch (exception& e) {
		cout << e.what() << endl;
	}
}
<commit_msg>remove useless "src" folder<commit_after><|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "utils.h"

#include <cmath>
#include <ios>

namespace utils {
  real* t_sigmoid;
  real* t_log;

  real log(real x) {
    if (x > 1.0) {
      return 0.0;
    }
    int i = int(x * LOG_TABLE_SIZE);
    return t_log[i];
  }

  real sigmoid(real x) {
    if (x < -MAX_SIGMOID) {
      return 0.0;
    } else if (x > MAX_SIGMOID) {
      return 1.0;
    } else {
      int i = int((x + MAX_SIGMOID) * SIGMOID_TABLE_SIZE / MAX_SIGMOID / 2);
      return t_sigmoid[i];
    }
  }

  void initTables() {
    initSigmoid();
    initLog();
  }

  void initSigmoid() {
    t_sigmoid = new real[SIGMOID_TABLE_SIZE + 1];
    for (int i = 0; i < SIGMOID_TABLE_SIZE + 1; i++) {
      real x = real(i * 2 * MAX_SIGMOID) / SIGMOID_TABLE_SIZE - MAX_SIGMOID;
      t_sigmoid[i] = 1.0 / (1.0 + std::exp(-x));
    }
  }

  void initLog() {
    t_log = new real[LOG_TABLE_SIZE + 1];
    for (int i = 0; i < LOG_TABLE_SIZE + 1; i++) {
      real x = (real(i) + 1e-5) / LOG_TABLE_SIZE;
      t_log[i] = std::log(x);
    }
  }

  void freeTables() {
    delete[] t_sigmoid;
    delete[] t_log;
  }

  int64_t size(std::ifstream& ifs) {
    ifs.seekg(std::streamoff(0), std::ios::end);
    return ifs.tellg();
  }

  void seek(std::ifstream& ifs, int64_t pos) {
    char c;
    ifs.clear();
    ifs.seekg(std::streampos(pos));
    do {
      ifs.get(c);
    } while (!iswspace(c));
  }
}
<commit_msg>Set the pointers of precomputed tables to nullptr in Utils after delete.<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "utils.h"

#include <cmath>
#include <ios>

namespace utils {
  real* t_sigmoid;
  real* t_log;

  real log(real x) {
    if (x > 1.0) {
      return 0.0;
    }
    int i = int(x * LOG_TABLE_SIZE);
    return t_log[i];
  }

  real sigmoid(real x) {
    if (x < -MAX_SIGMOID) {
      return 0.0;
    } else if (x > MAX_SIGMOID) {
      return 1.0;
    } else {
      int i = int((x + MAX_SIGMOID) * SIGMOID_TABLE_SIZE / MAX_SIGMOID / 2);
      return t_sigmoid[i];
    }
  }

  void initTables() {
    initSigmoid();
    initLog();
  }

  void initSigmoid() {
    t_sigmoid = new real[SIGMOID_TABLE_SIZE + 1];
    for (int i = 0; i < SIGMOID_TABLE_SIZE + 1; i++) {
      real x = real(i * 2 * MAX_SIGMOID) / SIGMOID_TABLE_SIZE - MAX_SIGMOID;
      t_sigmoid[i] = 1.0 / (1.0 + std::exp(-x));
    }
  }

  void initLog() {
    t_log = new real[LOG_TABLE_SIZE + 1];
    for (int i = 0; i < LOG_TABLE_SIZE + 1; i++) {
      real x = (real(i) + 1e-5) / LOG_TABLE_SIZE;
      t_log[i] = std::log(x);
    }
  }

  void freeTables() {
    delete[] t_sigmoid;
    delete[] t_log;
    t_sigmoid = nullptr;
    t_log = nullptr;
  }

  int64_t size(std::ifstream& ifs) {
    ifs.seekg(std::streamoff(0), std::ios::end);
    return ifs.tellg();
  }

  void seek(std::ifstream& ifs, int64_t pos) {
    char c;
    ifs.clear();
    ifs.seekg(std::streampos(pos));
    do {
      ifs.get(c);
    } while (!iswspace(c));
  }
}
<|endoftext|>


<commit_before>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Matei David (matei@cs.toronto.edu)
//---------------------------------------------------------

// Reference:
// http://stackoverflow.com/questions/14086417/how-to-write-custom-input-stream-in-c

#ifndef __ZSTR_HPP
#define __ZSTR_HPP

#include <cassert>
#include <fstream>
#include <sstream>
#include <zlib.h>
#include "strict_fstream.hpp"

namespace zstr
{

/// Exception class thrown by failed zlib operations.
class Exception
    : public std::exception
{
public:
    Exception(z_stream * zstrm_p, int ret)
        : _msg("zlib: ")
    {
        switch (ret)
        {
        case Z_STREAM_ERROR:
            _msg += "Z_STREAM_ERROR: ";
            break;
        case Z_DATA_ERROR:
            _msg += "Z_DATA_ERROR: ";
            break;
        case Z_MEM_ERROR:
            _msg += "Z_MEM_ERROR: ";
            break;
        case Z_VERSION_ERROR:
            _msg += "Z_VERSION_ERROR: ";
            break;
        case Z_BUF_ERROR:
            _msg += "Z_BUF_ERROR: ";
            break;
        default:
            std::ostringstream oss;
            oss << ret;
            _msg += "[" + oss.str() + "]: ";
            break;
        }
        _msg += zstrm_p->msg;
    }
    Exception(const std::string msg) : _msg(msg) {}
    const char * what() const noexcept { return _msg.c_str(); }
private:
    std::string _msg;
}; // class Exception

namespace detail
{

class z_stream_wrapper
    : public z_stream
{
public:
    z_stream_wrapper(bool _is_input = true, int _level = Z_DEFAULT_COMPRESSION)
        : is_input(_is_input)
    {
        this->zalloc = Z_NULL;
        this->zfree = Z_NULL;
        this->opaque = Z_NULL;
        int ret;
        if (is_input)
        {
            this->avail_in = 0;
            this->next_in = Z_NULL;
            ret = inflateInit2(this, 15+32);
        }
        else
        {
            ret = deflateInit2(this, _level, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY);
        }
        if (ret != Z_OK) throw Exception(this, ret);
    }
    ~z_stream_wrapper()
    {
        if (is_input)
        {
            inflateEnd(this);
        }
        else
        {
            deflateEnd(this);
        }
    }
private:
    bool is_input;
}; // class z_stream_wrapper

} // namespace detail

class istreambuf
    : public std::streambuf
{
public:
    istreambuf(std::streambuf * _sbuf_p,
               std::size_t _buff_size = default_buff_size, bool _auto_detect = true)
        : sbuf_p(_sbuf_p),
          zstrm_p(nullptr),
          buff_size(_buff_size),
          auto_detect(_auto_detect),
          auto_detect_run(false),
          is_text(false)
    {
        assert(sbuf_p);
        in_buff = new char [buff_size];
        in_buff_start = in_buff;
        in_buff_end = in_buff;
        out_buff = new char [buff_size];
        setg(out_buff, out_buff, out_buff);
    }

    istreambuf(const istreambuf &) = delete;
    istreambuf(istreambuf &&) = default;
    istreambuf & operator = (const istreambuf &) = delete;
    istreambuf & operator = (istreambuf &&) = default;

    virtual ~istreambuf()
    {
        delete [] in_buff;
        delete [] out_buff;
        if (zstrm_p) delete zstrm_p;
    }

    virtual std::streambuf::int_type underflow()
    {
        if (this->gptr() == this->egptr())
        {
            // pointers for free region in output buffer
            char * out_buff_free_start = out_buff;
            do
            {
                // read more input if none available
                if (in_buff_start == in_buff_end)
                {
                    // empty input buffer: refill from the start
                    in_buff_start = in_buff;
                    std::streamsize sz = sbuf_p->sgetn(in_buff, buff_size);
                    in_buff_end = in_buff + sz;
                    if (in_buff_end == in_buff_start) break; // end of input
                }
                // auto detect if the stream contains text or deflate data
                if (auto_detect && ! auto_detect_run)
                {
                    auto_detect_run = true;
                    unsigned char b0 = *reinterpret_cast< unsigned char * >(in_buff_start);
                    unsigned char b1 = *reinterpret_cast< unsigned char * >(in_buff_start + 1);
                    // Ref:
                    // http://en.wikipedia.org/wiki/Gzip
                    // http://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like
                    is_text = ! (in_buff_start + 2 <= in_buff_end
                                 && ((b0 == 0x1F && b1 == 0x8B)         // gzip header
                                     || (b0 == 0x78 && (b1 == 0x01      // zlib header
                                                        || b1 == 0x9C
                                                        || b1 == 0xDA))));
                }
                if (is_text)
                {
                    // simply swap in_buff and out_buff, and adjust pointers
                    assert(in_buff_start == in_buff);
                    std::swap(in_buff, out_buff);
                    out_buff_free_start = in_buff_end;
                    in_buff_start = in_buff;
                    in_buff_end = in_buff;
                }
                else
                {
                    // run inflate() on input
                    if (! zstrm_p) zstrm_p = new detail::z_stream_wrapper(true);
                    zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(in_buff_start);
                    zstrm_p->avail_in = in_buff_end - in_buff_start;
                    zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff_free_start);
                    zstrm_p->avail_out = (out_buff + buff_size) - out_buff_free_start;
                    int ret = inflate(zstrm_p, Z_NO_FLUSH);
                    // process return code
                    if (ret != Z_OK && ret != Z_STREAM_END) throw Exception(zstrm_p, ret);
                    // update in&out pointers following inflate()
                    in_buff_start = reinterpret_cast< decltype(in_buff_start) >(zstrm_p->next_in);
                    in_buff_end = in_buff_start + zstrm_p->avail_in;
                    out_buff_free_start = reinterpret_cast< decltype(out_buff_free_start) >(zstrm_p->next_out);
                    assert(out_buff_free_start + zstrm_p->avail_out == out_buff + buff_size);
                    // if stream ended, deallocate inflator
                    if (ret == Z_STREAM_END)
                    {
                        delete zstrm_p;
                        zstrm_p = nullptr;
                    }
                }
            } while (out_buff_free_start == out_buff);
            // 2 exit conditions:
            // - end of input: there might or might not be output available
            // - out_buff_free_start != out_buff: output available
            this->setg(out_buff, out_buff, out_buff_free_start);
        }
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*this->gptr());
    }
    static const std::size_t default_buff_size = (std::size_t)1 << 20;
private:
    std::streambuf * sbuf_p;
    char * in_buff;
    char * in_buff_start;
    char * in_buff_end;
    char * out_buff;
    detail::z_stream_wrapper * zstrm_p;
    std::size_t buff_size;
    bool auto_detect;
    bool auto_detect_run;
    bool is_text;

}; // class istreambuf

class ostreambuf
    : public std::streambuf
{
public:
    ostreambuf(std::streambuf * _sbuf_p,
               std::size_t _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION)
        : sbuf_p(_sbuf_p),
          zstrm_p(new detail::z_stream_wrapper(false, _level)),
          buff_size(_buff_size)
    {
        assert(sbuf_p);
        in_buff = new char [buff_size];
        out_buff = new char [buff_size];
        setp(in_buff, in_buff + buff_size);
    }

    ostreambuf(const ostreambuf &) = delete;
    ostreambuf(ostreambuf &&) = default;
    ostreambuf & operator = (const ostreambuf &) = delete;
    ostreambuf & operator = (ostreambuf &&) = default;

    int deflate_loop(int flush)
    {
        while (true)
        {
            zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff);
            zstrm_p->avail_out = buff_size;
            int ret = deflate(zstrm_p, flush);
            if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) throw Exception(zstrm_p, ret);
            std::streamsize sz = sbuf_p->sputn(out_buff, reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff);
            if (sz != reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff)
            {
                // there was an error in the sink stream
                return -1;
            }
            if (ret == Z_STREAM_END || ret == Z_BUF_ERROR || sz == 0)
            {
                break;
            }
        }
        return 0;
    }

    virtual ~ostreambuf()
    {
        // flush the zlib stream
        //
        // NOTE: Errors here (sync() return value not 0) are ignored, because we
        // cannot throw in a destructor. This mirrors the behaviour of
        // std::basic_filebuf::~basic_filebuf(). To see an exception on error,
        // close the ofstream with an explicit call to close(), and do not rely
        // on the implicit call in the destructor.
        //
        sync();
        delete [] in_buff;
        delete [] out_buff;
        delete zstrm_p;
    }
    virtual std::streambuf::int_type overflow(std::streambuf::int_type c = traits_type::eof())
    {
        zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(pbase());
        zstrm_p->avail_in = pptr() - pbase();
        while (zstrm_p->avail_in > 0)
        {
            int r = deflate_loop(Z_NO_FLUSH);
            if (r != 0)
            {
                setp(nullptr, nullptr);
                return traits_type::eof();
            }
        }
        setp(in_buff, in_buff + buff_size);
        return traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::eof() : sputc(c);
    }
    virtual int sync()
    {
        // first, call overflow to clear in_buff
        overflow();
        if (! pptr()) return -1;
        // then, call deflate asking to finish the zlib stream
        zstrm_p->next_in = nullptr;
        zstrm_p->avail_in = 0;
        if (deflate_loop(Z_FINISH) != 0) return -1;
        deflateReset(zstrm_p);
        return 0;
    }
    static const std::size_t default_buff_size = (std::size_t)1 << 20;
private:
    std::streambuf * sbuf_p;
    char * in_buff;
    char * out_buff;
    detail::z_stream_wrapper * zstrm_p;
    std::size_t buff_size;

}; // class ostreambuf

class istream
    : public std::istream
{
public:
    istream(std::istream & is)
        : std::istream(new istreambuf(is.rdbuf()))
    {
        exceptions(std::ios_base::badbit);
    }
    explicit istream(std::streambuf * sbuf_p)
        : std::istream(new istreambuf(sbuf_p))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~istream()
    {
        delete rdbuf();
    }
}; // class istream

class ostream
    : public std::ostream
{
public:
    ostream(std::ostream & os)
        : std::ostream(new ostreambuf(os.rdbuf()))
    {
        exceptions(std::ios_base::badbit);
    }
    explicit ostream(std::streambuf * sbuf_p)
        : std::ostream(new ostreambuf(sbuf_p))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~ostream()
    {
        delete rdbuf();
    }
}; // class ostream

namespace detail
{

template < typename FStream_Type >
struct strict_fstream_holder
{
    strict_fstream_holder(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
        : _fs(filename, mode)
    {}
    FStream_Type _fs;
}; // class strict_fstream_holder

} // namespace detail

class ifstream
    : private detail::strict_fstream_holder< strict_fstream::ifstream >,
      public std::istream
{
public:
    explicit ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in, size_t buff_size = istreambuf::default_buff_size)
        : detail::strict_fstream_holder< strict_fstream::ifstream >(filename, mode),
          std::istream(new istreambuf(_fs.rdbuf(), buff_size))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~ifstream()
    {
        if (_fs.is_open()) close();
        if (rdbuf()) delete rdbuf();
    }
    virtual void close()
    {
        _fs.close();
    }
    // Return the position within the compressed file
    streampos compressed_tellg()
    {
        return _fs.tellg();
    }
}; // class ifstream

class ofstream
    : private detail::strict_fstream_holder< strict_fstream::ofstream >,
      public std::ostream
{
public:
    explicit ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out, int compress_level = Z_DEFAULT_COMPRESSION, size_t buff_size = ostreambuf::default_buff_size)
        : detail::strict_fstream_holder< strict_fstream::ofstream >(filename, mode | std::ios_base::binary),
          std::ostream(new ostreambuf(_fs.rdbuf(), buff_size, compress_level))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~ofstream()
    {
        if (_fs.is_open()) close();
        if (rdbuf()) delete rdbuf();
    }
    virtual void close()
    {
        std::ostream::flush();
        _fs.close();
    }
    // Return the position within the compressed file
    streampos compressed_tellp()
    {
        return _fs.tellp();
    }
}; // class ofstream

} // namespace zstr

#endif
<commit_msg>fixed namespace issue<commit_after>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Matei David (matei@cs.toronto.edu)
//---------------------------------------------------------

// Reference:
// http://stackoverflow.com/questions/14086417/how-to-write-custom-input-stream-in-c

#ifndef __ZSTR_HPP
#define __ZSTR_HPP

#include <cassert>
#include <fstream>
#include <sstream>
#include <zlib.h>
#include "strict_fstream.hpp"

namespace zstr
{

/// Exception class thrown by failed zlib operations.
class Exception
    : public std::exception
{
public:
    Exception(z_stream * zstrm_p, int ret)
        : _msg("zlib: ")
    {
        switch (ret)
        {
        case Z_STREAM_ERROR:
            _msg += "Z_STREAM_ERROR: ";
            break;
        case Z_DATA_ERROR:
            _msg += "Z_DATA_ERROR: ";
            break;
        case Z_MEM_ERROR:
            _msg += "Z_MEM_ERROR: ";
            break;
        case Z_VERSION_ERROR:
            _msg += "Z_VERSION_ERROR: ";
            break;
        case Z_BUF_ERROR:
            _msg += "Z_BUF_ERROR: ";
            break;
        default:
            std::ostringstream oss;
            oss << ret;
            _msg += "[" + oss.str() + "]: ";
            break;
        }
        _msg += zstrm_p->msg;
    }
    Exception(const std::string msg) : _msg(msg) {}
    const char * what() const noexcept { return _msg.c_str(); }
private:
    std::string _msg;
}; // class Exception

namespace detail
{

class z_stream_wrapper
    : public z_stream
{
public:
    z_stream_wrapper(bool _is_input = true, int _level = Z_DEFAULT_COMPRESSION)
        : is_input(_is_input)
    {
        this->zalloc = Z_NULL;
        this->zfree = Z_NULL;
        this->opaque = Z_NULL;
        int ret;
        if (is_input)
        {
            this->avail_in = 0;
            this->next_in = Z_NULL;
            ret = inflateInit2(this, 15+32);
        }
        else
        {
            ret = deflateInit2(this, _level, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY);
        }
        if (ret != Z_OK) throw Exception(this, ret);
    }
    ~z_stream_wrapper()
    {
        if (is_input)
        {
            inflateEnd(this);
        }
        else
        {
            deflateEnd(this);
        }
    }
private:
    bool is_input;
}; // class z_stream_wrapper

} // namespace detail

class istreambuf
    : public std::streambuf
{
public:
    istreambuf(std::streambuf * _sbuf_p,
               std::size_t _buff_size = default_buff_size, bool _auto_detect = true)
        : sbuf_p(_sbuf_p),
          zstrm_p(nullptr),
          buff_size(_buff_size),
          auto_detect(_auto_detect),
          auto_detect_run(false),
          is_text(false)
    {
        assert(sbuf_p);
        in_buff = new char [buff_size];
        in_buff_start = in_buff;
        in_buff_end = in_buff;
        out_buff = new char [buff_size];
        setg(out_buff, out_buff, out_buff);
    }

    istreambuf(const istreambuf &) = delete;
    istreambuf(istreambuf &&) = default;
    istreambuf & operator = (const istreambuf &) = delete;
    istreambuf & operator = (istreambuf &&) = default;

    virtual ~istreambuf()
    {
        delete [] in_buff;
        delete [] out_buff;
        if (zstrm_p) delete zstrm_p;
    }

    virtual std::streambuf::int_type underflow()
    {
        if (this->gptr() == this->egptr())
        {
            // pointers for free region in output buffer
            char * out_buff_free_start = out_buff;
            do
            {
                // read more input if none available
                if (in_buff_start == in_buff_end)
                {
                    // empty input buffer: refill from the start
                    in_buff_start = in_buff;
                    std::streamsize sz = sbuf_p->sgetn(in_buff, buff_size);
                    in_buff_end = in_buff + sz;
                    if (in_buff_end == in_buff_start) break; // end of input
                }
                // auto detect if the stream contains text or deflate data
                if (auto_detect && ! auto_detect_run)
                {
                    auto_detect_run = true;
                    unsigned char b0 = *reinterpret_cast< unsigned char * >(in_buff_start);
                    unsigned char b1 = *reinterpret_cast< unsigned char * >(in_buff_start + 1);
                    // Ref:
                    // http://en.wikipedia.org/wiki/Gzip
                    // http://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like
                    is_text = ! (in_buff_start + 2 <= in_buff_end
                                 && ((b0 == 0x1F && b1 == 0x8B)         // gzip header
                                     || (b0 == 0x78 && (b1 == 0x01      // zlib header
                                                        || b1 == 0x9C
                                                        || b1 == 0xDA))));
                }
                if (is_text)
                {
                    // simply swap in_buff and out_buff, and adjust pointers
                    assert(in_buff_start == in_buff);
                    std::swap(in_buff, out_buff);
                    out_buff_free_start = in_buff_end;
                    in_buff_start = in_buff;
                    in_buff_end = in_buff;
                }
                else
                {
                    // run inflate() on input
                    if (! zstrm_p) zstrm_p = new detail::z_stream_wrapper(true);
                    zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(in_buff_start);
                    zstrm_p->avail_in = in_buff_end - in_buff_start;
                    zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff_free_start);
                    zstrm_p->avail_out = (out_buff + buff_size) - out_buff_free_start;
                    int ret = inflate(zstrm_p, Z_NO_FLUSH);
                    // process return code
                    if (ret != Z_OK && ret != Z_STREAM_END) throw Exception(zstrm_p, ret);
                    // update in&out pointers following inflate()
                    in_buff_start = reinterpret_cast< decltype(in_buff_start) >(zstrm_p->next_in);
                    in_buff_end = in_buff_start + zstrm_p->avail_in;
                    out_buff_free_start = reinterpret_cast< decltype(out_buff_free_start) >(zstrm_p->next_out);
                    assert(out_buff_free_start + zstrm_p->avail_out == out_buff + buff_size);
                    // if stream ended, deallocate inflator
                    if (ret == Z_STREAM_END)
                    {
                        delete zstrm_p;
                        zstrm_p = nullptr;
                    }
                }
            } while (out_buff_free_start == out_buff);
            // 2 exit conditions:
            // - end of input: there might or might not be output available
            // - out_buff_free_start != out_buff: output available
            this->setg(out_buff, out_buff, out_buff_free_start);
        }
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*this->gptr());
    }
    static const std::size_t default_buff_size = (std::size_t)1 << 20;
private:
    std::streambuf * sbuf_p;
    char * in_buff;
    char * in_buff_start;
    char * in_buff_end;
    char * out_buff;
    detail::z_stream_wrapper * zstrm_p;
    std::size_t buff_size;
    bool auto_detect;
    bool auto_detect_run;
    bool is_text;

}; // class istreambuf

class ostreambuf
    : public std::streambuf
{
public:
    ostreambuf(std::streambuf * _sbuf_p,
               std::size_t _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION)
        : sbuf_p(_sbuf_p),
          zstrm_p(new detail::z_stream_wrapper(false, _level)),
          buff_size(_buff_size)
    {
        assert(sbuf_p);
        in_buff = new char [buff_size];
        out_buff = new char [buff_size];
        setp(in_buff, in_buff + buff_size);
    }

    ostreambuf(const ostreambuf &) = delete;
    ostreambuf(ostreambuf &&) = default;
    ostreambuf & operator = (const ostreambuf &) = delete;
    ostreambuf & operator = (ostreambuf &&) = default;

    int deflate_loop(int flush)
    {
        while (true)
        {
            zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff);
            zstrm_p->avail_out = buff_size;
            int ret = deflate(zstrm_p, flush);
            if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) throw Exception(zstrm_p, ret);
            std::streamsize sz = sbuf_p->sputn(out_buff, reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff);
            if (sz != reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff)
            {
                // there was an error in the sink stream
                return -1;
            }
            if (ret == Z_STREAM_END || ret == Z_BUF_ERROR || sz == 0)
            {
                break;
            }
        }
        return 0;
    }

    virtual ~ostreambuf()
    {
        // flush the zlib stream
        //
        // NOTE: Errors here (sync() return value not 0) are ignored, because we
        // cannot throw in a destructor. This mirrors the behaviour of
        // std::basic_filebuf::~basic_filebuf(). To see an exception on error,
        // close the ofstream with an explicit call to close(), and do not rely
        // on the implicit call in the destructor.
        //
        sync();
        delete [] in_buff;
        delete [] out_buff;
        delete zstrm_p;
    }
    virtual std::streambuf::int_type overflow(std::streambuf::int_type c = traits_type::eof())
    {
        zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(pbase());
        zstrm_p->avail_in = pptr() - pbase();
        while (zstrm_p->avail_in > 0)
        {
            int r = deflate_loop(Z_NO_FLUSH);
            if (r != 0)
            {
                setp(nullptr, nullptr);
                return traits_type::eof();
            }
        }
        setp(in_buff, in_buff + buff_size);
        return traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::eof() : sputc(c);
    }
    virtual int sync()
    {
        // first, call overflow to clear in_buff
        overflow();
        if (! pptr()) return -1;
        // then, call deflate asking to finish the zlib stream
        zstrm_p->next_in = nullptr;
        zstrm_p->avail_in = 0;
        if (deflate_loop(Z_FINISH) != 0) return -1;
        deflateReset(zstrm_p);
        return 0;
    }
    static const std::size_t default_buff_size = (std::size_t)1 << 20;
private:
    std::streambuf * sbuf_p;
    char * in_buff;
    char * out_buff;
    detail::z_stream_wrapper * zstrm_p;
    std::size_t buff_size;

}; // class ostreambuf

class istream
    : public std::istream
{
public:
    istream(std::istream & is)
        : std::istream(new istreambuf(is.rdbuf()))
    {
        exceptions(std::ios_base::badbit);
    }
    explicit istream(std::streambuf * sbuf_p)
        : std::istream(new istreambuf(sbuf_p))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~istream()
    {
        delete rdbuf();
    }
}; // class istream

class ostream
    : public std::ostream
{
public:
    ostream(std::ostream & os)
        : std::ostream(new ostreambuf(os.rdbuf()))
    {
        exceptions(std::ios_base::badbit);
    }
    explicit ostream(std::streambuf * sbuf_p)
        : std::ostream(new ostreambuf(sbuf_p))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~ostream()
    {
        delete rdbuf();
    }
}; // class ostream

namespace detail
{

template < typename FStream_Type >
struct strict_fstream_holder
{
    strict_fstream_holder(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
        : _fs(filename, mode)
    {}
    FStream_Type _fs;
}; // class strict_fstream_holder

} // namespace detail

class ifstream
    : private detail::strict_fstream_holder< strict_fstream::ifstream >,
      public std::istream
{
public:
    explicit ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in, size_t buff_size = istreambuf::default_buff_size)
        : detail::strict_fstream_holder< strict_fstream::ifstream >(filename, mode),
          std::istream(new istreambuf(_fs.rdbuf(), buff_size))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~ifstream()
    {
        if (_fs.is_open()) close();
        if (rdbuf()) delete rdbuf();
    }
    virtual void close()
    {
        _fs.close();
    }
    // Return the position within the compressed file
    std::streampos compressed_tellg()
    {
        return _fs.tellg();
    }
}; // class ifstream

class ofstream
    : private detail::strict_fstream_holder< strict_fstream::ofstream >,
      public std::ostream
{
public:
    explicit ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out, int compress_level = Z_DEFAULT_COMPRESSION, size_t buff_size = ostreambuf::default_buff_size)
        : detail::strict_fstream_holder< strict_fstream::ofstream >(filename, mode | std::ios_base::binary),
          std::ostream(new ostreambuf(_fs.rdbuf(), buff_size, compress_level))
    {
        exceptions(std::ios_base::badbit);
    }
    virtual ~ofstream()
    {
        if (_fs.is_open()) close();
        if (rdbuf()) delete rdbuf();
    }
    virtual void close()
    {
        std::ostream::flush();
        _fs.close();
    }
    // Return the position within the compressed file
    std::streampos compressed_tellp()
    {
        return _fs.tellp();
    }
}; // class ofstream

} // namespace zstr

#endif
<|endoftext|>


<commit_before>#include <stdio.h>
#include "../include/machine.h"
#include "machine.cpp"

#include "../include/debugC.h"

#include "../include/replEnvironment.h"
#include "replEnvironment.cpp"

#define CATCH_CONFIG_MAIN
#include "../include/catch.hpp"

TEST_CASE("Creating and running a machine", "[machine]"){
	string source = "+++>++[-<+>]<.";
	machine* testBFM = new machine(30000, true, false, source);

	REQUIRE_FALSE(testBFM == NULL);

	testBFM->processSource();

	REQUIRE(testBFM->getDataPointer() == 0);
	REQUIRE(testBFM->getTapeAt(0) == 5);

	FILE* abyss = fopen("/dev/null", "w");
	REQUIRE(testBFM->NAO(abyss) == 5);
	fclose(abyss);

	delete testBFM;
}

TEST_CASE("Create and manually modify a machine", "[machine]"){
	string source = "+++";
	machine *BFM = new machine(30000, true, false, source);

	REQUIRE_FALSE(BFM == NULL);

	BFM->processSource();
	REQUIRE(BFM->getDataPointer() == 0);
	REQUIRE(BFM->getTapeAt(0) == 3);

	REQUIRE(BFM->modifyDataPointer(1) == 1);
	REQUIRE(BFM->getDataPointer() == 1);
	REQUIRE(BFM->modifyDataPointer(2) == 2);
	REQUIRE(BFM->getDataPointer() == 2);
	REQUIRE(BFM->getTapeAt(BFM->getDataPointer()) == 0);

	REQUIRE(BFM->getSource() == "+++");
	char* moreSource = (char*)malloc(4); strcpy(moreSource, ">--");
	BFM->addToSource(moreSource);
	REQUIRE(BFM->getSource() == "+++>--");

	BFM->processSource();
	REQUIRE(BFM->getTapeAt(BFM->getDataPointer()) == -2);

	strcpy(moreSource, "++++");
	BFM->addToSource(moreSource);
	REQUIRE(BFM->getSource() == "+++>--++++");

	BFM->processSource();
	REQUIRE(BFM->getTapeAt(BFM->getDataPointer()) == 2);

	REQUIRE(BFM->incCell() == 3);
	REQUIRE(BFM->decCell() == 2);
	REQUIRE(BFM->decCell() == 1);
	REQUIRE(BFM->decCell() == 0);
	REQUIRE(BFM->incCell() == 1);

	REQUIRE(BFM->modifyDataPointer(0) == 0);
	REQUIRE(BFM->incPointer() == 1);
	REQUIRE(BFM->modifyTape(1, 0) == 0);
	REQUIRE(BFM->decPointer() == 0);

	delete BFM;
}

TEST_CASE("Process code char by char", "[machine]"){
	string source = "+-+-+-+";
	machine *BFM = new machine(30000, true, false, source);

	REQUIRE_FALSE(BFM == NULL);
	REQUIRE((char)BFM->processChar(1) == '+');
	REQUIRE((char)BFM->processChar(1) == '-');
	REQUIRE((char)BFM->processChar(1) == '+');
	REQUIRE((char)BFM->processChar(1) == '-');
	REQUIRE((char)BFM->processChar(1) == '+');
	REQUIRE((char)BFM->processChar(1) == '-');
	REQUIRE((char)BFM->processChar(1) == '+');

	REQUIRE(BFM->getTapeAt(0) == 1);

	delete BFM;
}

TEST_CASE("Changing the loop stack", "[machine][looping]"){
	string source = "+++[-]";
	machine *BFM = new machine(30000, true, false, source);
	REQUIRE_FALSE(BFM == NULL);

	BFM->processChar(1);
	BFM->processChar(1);
	BFM->processChar(1);
	BFM->processChar(1);

	for(int i = 0; i < 3; i++){
		REQUIRE(BFM->getStackTop() == 0);
		BFM->processChar(1);
		BFM->processChar(1);
		REQUIRE(BFM->getStackTop() == -1);
		BFM->processChar(1);
	}

}

TEST_CASE("Create a REPL environment", "[REPL]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	delete TRE;
}

TEST_CASE("Execution from REPL", "[REPL]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* source = (char*)malloc(32);
	strcpy(source, "++++++");
	TRE->process(source);
	REQUIRE((TRE->getMachine()->getTapeAt(0)) == 6);

	strcpy(source, "+++[-]");
	TRE->process(source);
	REQUIRE((TRE->getMachine()->getTapeAt(0)) == 0);

	delete TRE;
}

TEST_CASE("Recognize attempts to bind a name", "[REPL][bindings]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* testBinding = (char*)malloc(32);
	strcpy(testBinding, "adder=,>,[-<+>]<.");
	REQUIRE((TRE->tryingToBind(testBinding)));

	strcpy(testBinding, "echoUntilZero=[,.]");
	REQUIRE((TRE->tryingToBind(testBinding)));

	strcpy(testBinding, "notabinding");
	REQUIRE_FALSE((TRE->tryingToBind(testBinding)));

	strcpy(testBinding, "+++++[-]");
	REQUIRE_FALSE((TRE->tryingToBind(testBinding)));

	delete TRE;
}

TEST_CASE("Recognize existing bindings", "[REPL][bindings]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* potentialKey = (char*)malloc(32);

	strcpy(potentialKey, "pushRightOne");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), "[->+<]") == 0);
	strcpy(potentialKey, "add");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), ",>, pushLeftOne .<.") == 0);

	strcpy(potentialKey, "definitelyNotBound");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), potentialKey) == 0);
	strcpy(potentialKey, "notBoundEither");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), potentialKey) == 0);

	delete TRE;
}

TEST_CASE("Add or replace bindings", "[REPL][bindings]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* potentialBinding = (char*)malloc(32);
	strcpy(potentialBinding, "test=+++.");
	REQUIRE(TRE->addNewProcedure(potentialBinding));
	strcpy(potentialBinding, "+=-");
	REQUIRE(TRE->addNewProcedure(potentialBinding));
	strcpy(potentialBinding, "test=++++[-].");
	REQUIRE(TRE->addNewProcedure(potentialBinding));
	delete TRE;
}
<commit_msg>Started testing options<commit_after>#include <stdio.h>
#include "../include/machine.h"
#include "machine.cpp"

#include "../include/debugC.h"

#include "../include/replEnvironment.h"
#include "replEnvironment.cpp"

#define CATCH_CONFIG_MAIN
#include "../include/catch.hpp"

TEST_CASE("Creating and running a machine", "[machine]"){
	string source = "+++>++[-<+>]<.";
	machine* testBFM = new machine(30000, true, false, source);

	REQUIRE_FALSE(testBFM == NULL);

	testBFM->processSource();

	REQUIRE(testBFM->getDataPointer() == 0);
	REQUIRE(testBFM->getTapeAt(0) == 5);

	FILE* abyss = fopen("/dev/null", "w");
	REQUIRE(testBFM->NAO(abyss) == 5);
	fclose(abyss);

	delete testBFM;
}

TEST_CASE("Create and manually modify a machine", "[machine]"){
	string source = "+++";
	machine *BFM = new machine(30000, true, false, source);

	REQUIRE_FALSE(BFM == NULL);

	BFM->processSource();
	REQUIRE(BFM->getDataPointer() == 0);
	REQUIRE(BFM->getTapeAt(0) == 3);

	REQUIRE(BFM->modifyDataPointer(1) == 1);
	REQUIRE(BFM->getDataPointer() == 1);
	REQUIRE(BFM->modifyDataPointer(2) == 2);
	REQUIRE(BFM->getDataPointer() == 2);
	REQUIRE(BFM->getTapeAt(BFM->getDataPointer()) == 0);

	REQUIRE(BFM->getSource() == "+++");
	char* moreSource = (char*)malloc(4); strcpy(moreSource, ">--");
	BFM->addToSource(moreSource);
	REQUIRE(BFM->getSource() == "+++>--");

	BFM->processSource();
	REQUIRE(BFM->getTapeAt(BFM->getDataPointer()) == -2);

	strcpy(moreSource, "++++");
	BFM->addToSource(moreSource);
	REQUIRE(BFM->getSource() == "+++>--++++");

	BFM->processSource();
	REQUIRE(BFM->getTapeAt(BFM->getDataPointer()) == 2);

	REQUIRE(BFM->incCell() == 3);
	REQUIRE(BFM->decCell() == 2);
	REQUIRE(BFM->decCell() == 1);
	REQUIRE(BFM->decCell() == 0);
	REQUIRE(BFM->incCell() == 1);

	REQUIRE(BFM->modifyDataPointer(0) == 0);
	REQUIRE(BFM->incPointer() == 1);
	REQUIRE(BFM->modifyTape(1, 0) == 0);
	REQUIRE(BFM->decPointer() == 0);

	delete BFM;
}

TEST_CASE("Process code char by char", "[machine]"){
	string source = "+-+-+-+";
	machine *BFM = new machine(30000, true, false, source);

	REQUIRE_FALSE(BFM == NULL);
	REQUIRE((char)BFM->processChar(1) == '+');
	REQUIRE((char)BFM->processChar(1) == '-');
	REQUIRE((char)BFM->processChar(1) == '+');
	REQUIRE((char)BFM->processChar(1) == '-');
	REQUIRE((char)BFM->processChar(1) == '+');
	REQUIRE((char)BFM->processChar(1) == '-');
	REQUIRE((char)BFM->processChar(1) == '+');

	REQUIRE(BFM->getTapeAt(0) == 1);

	delete BFM;
}

TEST_CASE("Changing the loop stack", "[machine][looping]"){
	string source = "+++[-]";
	machine *BFM = new machine(30000, true, false, source);
	REQUIRE_FALSE(BFM == NULL);

	BFM->processChar(1);
	BFM->processChar(1);
	BFM->processChar(1);
	BFM->processChar(1);

	for(int i = 0; i < 3; i++){
		REQUIRE(BFM->getStackTop() == 0);
		BFM->processChar(1);
		BFM->processChar(1);
		REQUIRE(BFM->getStackTop() == -1);
		BFM->processChar(1);
	}

}

TEST_CASE("Create a REPL environment", "[REPL]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	delete TRE;
}

TEST_CASE("Execution from REPL", "[REPL]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* source = (char*)malloc(32);
	strcpy(source, "++++++");
	TRE->process(source);
	REQUIRE((TRE->getMachine()->getTapeAt(0)) == 6);

	strcpy(source, "+++[-]");
	TRE->process(source);
	REQUIRE((TRE->getMachine()->getTapeAt(0)) == 0);

	delete TRE;
}

TEST_CASE("Recognize attempts to bind a name", "[REPL][bindings]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* testBinding = (char*)malloc(32);
	strcpy(testBinding, "adder=,>,[-<+>]<.");
	REQUIRE((TRE->tryingToBind(testBinding)));

	strcpy(testBinding, "echoUntilZero=[,.]");
	REQUIRE((TRE->tryingToBind(testBinding)));

	strcpy(testBinding, "notabinding");
	REQUIRE_FALSE((TRE->tryingToBind(testBinding)));

	strcpy(testBinding, "+++++[-]");
	REQUIRE_FALSE((TRE->tryingToBind(testBinding)));

	delete TRE;
}

TEST_CASE("Recognize existing bindings", "[REPL][bindings]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* potentialKey = (char*)malloc(32);

	strcpy(potentialKey, "pushRightOne");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), "[->+<]") == 0);
	strcpy(potentialKey, "add");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), ",>, pushLeftOne .<.") == 0);

	strcpy(potentialKey, "definitelyNotBound");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), potentialKey) == 0);
	strcpy(potentialKey, "notBoundEither");
	REQUIRE(strcmp(TRE->expandProcedure(potentialKey), potentialKey) == 0);

	delete TRE;
}

TEST_CASE("Add or replace bindings", "[REPL][bindings]"){
	replEnvironment* TRE = new replEnvironment(false, true, 30000);
	REQUIRE_FALSE(TRE == NULL);

	char* potentialBinding = (char*)malloc(32);
	strcpy(potentialBinding, "test=+++.");
	REQUIRE(TRE->addNewProcedure(potentialBinding));
	strcpy(potentialBinding, "+=-");
	REQUIRE(TRE->addNewProcedure(potentialBinding));
	strcpy(potentialBinding, "test=++++[-].");
	REQUIRE(TRE->addNewProcedure(potentialBinding));
	delete TRE;
}

TEST_CASE("Prove I can do ASCII output or not", "[machine][options][ASCII]"){
	string source = "+++++[->+++++++++++++<]>"; //65, ASCII 'A'
	machine *BFM = new machine(30000, true, false, source);

	FILE* abyss = fopen("/dev/null", "w");
	BFM->processSource();
	REQUIRE((BFM->*BFM->output)(abyss) == 65);
	delete BFM;

	BFM = new machine(30000, true, true, source);
	BFM->processSource();
	REQUIRE((BFM->*BFM->output)(abyss) == 'A');
	delete BFM;

	fclose(abyss);
}

<|endoftext|>