<commit_before>// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "runtime-profiler.h"

#include "assembler.h"
#include "code-stubs.h"
#include "compilation-cache.h"
#include "deoptimizer.h"
#include "execution.h"
#include "global-handles.h"
#include "scopeinfo.h"
#include "top.h"

namespace v8 {
namespace internal {

class PendingListNode : public Malloced {
 public:
  explicit PendingListNode(JSFunction* function);
  ~PendingListNode() { Destroy(); }

  PendingListNode* next() const { return next_; }
  void set_next(PendingListNode* node) { next_ = node; }
  Handle<JSFunction> function() { return Handle<JSFunction>::cast(function_); }

  // If the function is garbage collected before we've had the chance
  // to optimize it the weak handle will be null.
  bool IsValid() { return !function_.is_null(); }

  // Returns the number of microseconds this node has been pending.
  int Delay() const { return static_cast<int>(OS::Ticks() - start_); }

 private:
  void Destroy();
  static void WeakCallback(v8::Persistent<v8::Value> object, void* data);

  PendingListNode* next_;
  Handle<Object> function_;  // Weak handle.
  int64_t start_;
};

enum SamplerState {
  IN_NON_JS_STATE = 0,
  IN_JS_STATE = 1
};

// Optimization sampler constants.
static const int kSamplerFrameCount = 2;
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
static const int kSamplerWindowSize = 16;

static const int kSamplerTicksBetweenThresholdAdjustment = 32;

static const int kSamplerThresholdInit = 3;
static const int kSamplerThresholdMin = 1;
static const int kSamplerThresholdDelta = 1;

static const int kSamplerThresholdSizeFactorInit = 3;
static const int kSamplerThresholdSizeFactorMin = 1;
static const int kSamplerThresholdSizeFactorDelta = 1;

static const int kSizeLimit = 1500;

static int sampler_threshold = kSamplerThresholdInit;
static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;

static int sampler_ticks_until_threshold_adjustment =
    kSamplerTicksBetweenThresholdAdjustment;

// The ratio of ticks spent in JS code in percent.
static Atomic32 js_ratio;

// The JSFunctions in the sampler window are not GC safe. Old-space
// pointers are not cleared during mark-sweep collection and therefore
// the window might contain stale pointers. The window is updated on
// scavenges and (parts of it) cleared on mark-sweep and
// mark-sweep-compact.
static Object* sampler_window[kSamplerWindowSize] = { NULL, };
static int sampler_window_position = 0;
static int sampler_window_weight[kSamplerWindowSize] = { 0, };

// Support for pending 'optimize soon' requests.
static PendingListNode* optimize_soon_list = NULL;

PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) {
  function_ = GlobalHandles::Create(function);
  start_ = OS::Ticks();
  GlobalHandles::MakeWeak(function_.location(), this, &WeakCallback);
}

void PendingListNode::Destroy() {
  if (!IsValid()) return;
  GlobalHandles::Destroy(function_.location());
  function_= Handle<Object>::null();
}

void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) {
  reinterpret_cast<PendingListNode*>(data)->Destroy();
}

static bool IsOptimizable(JSFunction* function) {
  Code* code = function->code();
  return code->kind() == Code::FUNCTION && code->optimizable();
}

static void Optimize(JSFunction* function, bool eager, int delay) {
  ASSERT(IsOptimizable(function));
  if (FLAG_trace_opt) {
    PrintF("[marking (%s) ", eager ? "eagerly" : "lazily");
    function->PrintName();
    PrintF(" for recompilation");
    if (delay > 0) {
      PrintF(" (delayed %0.3f ms)", static_cast<double>(delay) / 1000);
    }
    PrintF("]\n");
  }

  // The next call to the function will trigger optimization.
  function->MarkForLazyRecompilation();
}

static void AttemptOnStackReplacement(JSFunction* function) {
  // See AlwaysFullCompiler (in compiler.cc) comment on why we need
  // Debug::has_break_points().
  ASSERT(function->IsMarkedForLazyRecompilation());
  if (!FLAG_use_osr || Debug::has_break_points() || function->IsBuiltin()) {
    return;
  }

  SharedFunctionInfo* shared = function->shared();
  // If the code is not optimizable, don't try OSR.
  if (!shared->code()->optimizable()) return;

  // We are not prepared to do OSR for a function that already has an
  // allocated arguments object.  The optimized code would bypass it for
  // arguments accesses, which is unsound.  Don't try OSR.
  if (shared->scope_info()->HasArgumentsShadow()) return;

  // We're using on-stack replacement: patch the unoptimized code so that
  // any back edge in any unoptimized frame will trigger on-stack
  // replacement for that frame.
  if (FLAG_trace_osr) {
    PrintF("[patching stack checks in ");
    function->PrintName();
    PrintF(" for on-stack replacement]\n");
  }

  // Get the stack check stub code object to match against.  We aren't
  // prepared to generate it, but we don't expect to have to.
  StackCheckStub check_stub;
  Object* check_code;
  MaybeObject* maybe_check_code = check_stub.TryGetCode();
  if (maybe_check_code->ToObject(&check_code)) {
    Code* replacement_code = Builtins::builtin(Builtins::OnStackReplacement);
    Code* unoptimized_code = shared->code();
    // Iterate the unoptimized code and patch every stack check except at
    // the function entry.  This code assumes the function entry stack
    // check appears first i.e., is not deferred or otherwise reordered.
    bool first = true;
    for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask);
         !it.done();
         it.next()) {
      RelocInfo* rinfo = it.rinfo();
      if (rinfo->target_address() == Code::cast(check_code)->entry()) {
        if (first) {
          first = false;
        } else {
          Deoptimizer::PatchStackCheckCode(rinfo, replacement_code);
        }
      }
    }
  }
}

static void ClearSampleBuffer() {
  for (int i = 0; i < kSamplerWindowSize; i++) {
    sampler_window[i] = NULL;
    sampler_window_weight[i] = 0;
  }
}

static void ClearSampleBufferNewSpaceEntries() {
  for (int i = 0; i < kSamplerWindowSize; i++) {
    if (Heap::InNewSpace(sampler_window[i])) {
      sampler_window[i] = NULL;
      sampler_window_weight[i] = 0;
    }
  }
}

static int LookupSample(JSFunction* function) {
  int weight = 0;
  for (int i = 0; i < kSamplerWindowSize; i++) {
    Object* sample = sampler_window[i];
    if (sample != NULL) {
      if (function == sample) {
        weight += sampler_window_weight[i];
      }
    }
  }
  return weight;
}

static void AddSample(JSFunction* function, int weight) {
  ASSERT(IsPowerOf2(kSamplerWindowSize));
  sampler_window[sampler_window_position] = function;
  sampler_window_weight[sampler_window_position] = weight;
  sampler_window_position = (sampler_window_position + 1) &
      (kSamplerWindowSize - 1);
}

void RuntimeProfiler::OptimizeNow() {
  HandleScope scope;
  PendingListNode* current = optimize_soon_list;
  while (current != NULL) {
    PendingListNode* next = current->next();
    if (current->IsValid()) {
      Handle<JSFunction> function = current->function();
      int delay = current->Delay();
      if (IsOptimizable(*function)) {
        Optimize(*function, true, delay);
      }
    }
    delete current;
    current = next;
  }
  optimize_soon_list = NULL;

  // Run through the JavaScript frames and collect them. If we already
  // have a sample of the function, we mark it for optimizations
  // (eagerly or lazily).
  JSFunction* samples[kSamplerFrameCount];
  int count = 0;
  for (JavaScriptFrameIterator it;
       count < kSamplerFrameCount && !it.done();
       it.Advance()) {
    JavaScriptFrame* frame = it.frame();
    JSFunction* function = JSFunction::cast(frame->function());

    // Adjust threshold each time we have processed
    // a certain number of ticks.
    if (sampler_ticks_until_threshold_adjustment > 0) {
      sampler_ticks_until_threshold_adjustment--;
      if (sampler_ticks_until_threshold_adjustment <= 0) {
        // If the threshold is not already at the minimum
        // modify and reset the ticks until next adjustment.
        if (sampler_threshold > kSamplerThresholdMin) {
          sampler_threshold -= kSamplerThresholdDelta;
          sampler_ticks_until_threshold_adjustment =
              kSamplerTicksBetweenThresholdAdjustment;
        }
      }
    }

    if (function->IsMarkedForLazyRecompilation()) {
      Code* unoptimized = function->shared()->code();
      int nesting = unoptimized->allow_osr_at_loop_nesting_level();
      if (nesting == 0) AttemptOnStackReplacement(function);
      int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
      unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting);
    }

    // Do not record non-optimizable functions.
    if (!IsOptimizable(function)) continue;
    samples[count++] = function;

    int function_size = function->shared()->SourceSize();
    int threshold_size_factor = (function_size > kSizeLimit)
        ? sampler_threshold_size_factor
        : 1;

    int threshold = sampler_threshold * threshold_size_factor;
    int current_js_ratio = NoBarrier_Load(&js_ratio);

    // Adjust threshold depending on the ratio of time spent
    // in JS code.
    if (current_js_ratio < 20) {
      // If we spend less than 20% of the time in JS code,
      // do not optimize.
      continue;
    } else if (current_js_ratio < 75) {
      // Below 75% of time spent in JS code, only optimize very
      // frequently used functions.
      threshold *= 3;
    }

    if (LookupSample(function) >= threshold) {
      Optimize(function, false, 0);
      CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
    }
  }

  // Add the collected functions as samples. It's important not to do
  // this as part of collecting them because this will interfere with
  // the sample lookup in case of recursive functions.
  for (int i = 0; i < count; i++) {
    AddSample(samples[i], kSamplerFrameWeight[i]);
  }
}

void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
  if (!IsOptimizable(function)) return;
  PendingListNode* node = new PendingListNode(function);
  node->set_next(optimize_soon_list);
  optimize_soon_list = node;
}

void RuntimeProfiler::NotifyTick() {
  StackGuard::RequestRuntimeProfilerTick();
}

void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) {
  if (is_compacting) {
    // Clear all samples before mark-sweep-compact because every
    // function might move.
    ClearSampleBuffer();
  } else {
    // Clear only new space entries on mark-sweep since none of the
    // old-space functions will move.
    ClearSampleBufferNewSpaceEntries();
  }
}

bool IsEqual(void* first, void* second) {
  return first == second;
}

void RuntimeProfiler::Setup() {
  ClearSampleBuffer();
  // If the ticker hasn't already started, make sure to do so to get
  // the ticks for the runtime profiler.
  if (IsEnabled()) Logger::EnsureTickerStarted();
}

void RuntimeProfiler::Reset() {
  sampler_threshold = kSamplerThresholdInit;
  sampler_ticks_until_threshold_adjustment =
      kSamplerTicksBetweenThresholdAdjustment;
  sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
}

void RuntimeProfiler::TearDown() {
  // Nothing to do.
}

Object** RuntimeProfiler::SamplerWindowAddress() {
  return sampler_window;
}

int RuntimeProfiler::SamplerWindowSize() {
  return kSamplerWindowSize;
}

static void AddStateSample(SamplerState current_state) {
  static const int kStateWindowSize = 128;
  static SamplerState state_window[kStateWindowSize];
  static int state_window_position = 0;
  static int state_counts[2] = { kStateWindowSize, 0 };

  SamplerState old_state = state_window[state_window_position];
  state_counts[old_state]--;
  state_window[state_window_position] = current_state;
  state_counts[current_state]++;
  ASSERT(IsPowerOf2(kStateWindowSize));
  state_window_position = (state_window_position + 1) &
      (kStateWindowSize - 1);
  NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 /
                  kStateWindowSize);
}

bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
  static const int kNonJSTicksThreshold = 100;
  // We suspend the runtime profiler thread when not running
  // JavaScript. If the CPU profiler is active we must not do this
  // because it samples both JavaScript and C++ code.
  if (RuntimeProfiler::IsEnabled() &&
      !CpuProfiler::is_profiling() &&
      !(FLAG_prof && FLAG_prof_auto)) {
    if (Top::IsInJSState()) {
      AddStateSample(IN_JS_STATE);
      non_js_ticks_ = 0;
    } else {
      AddStateSample(IN_NON_JS_STATE);
      if (non_js_ticks_ < kNonJSTicksThreshold) {
        ++non_js_ticks_;
      } else {
        if (Top::WaitForJSState()) return true;
      }
    }
  }
  return false;
}

} }  // namespace v8::internal
<commit_msg>Fix a bug that caused the runtime profiler to sample huge amounts of stack frames in programs with recursively called optimized functions.<commit_after>// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "runtime-profiler.h"

#include "assembler.h"
#include "code-stubs.h"
#include "compilation-cache.h"
#include "deoptimizer.h"
#include "execution.h"
#include "global-handles.h"
#include "scopeinfo.h"
#include "top.h"

namespace v8 {
namespace internal {

class PendingListNode : public Malloced {
 public:
  explicit PendingListNode(JSFunction* function);
  ~PendingListNode() { Destroy(); }

  PendingListNode* next() const { return next_; }
  void set_next(PendingListNode* node) { next_ = node; }
  Handle<JSFunction> function() { return Handle<JSFunction>::cast(function_); }

  // If the function is garbage collected before we've had the chance
  // to optimize it the weak handle will be null.
  bool IsValid() { return !function_.is_null(); }

  // Returns the number of microseconds this node has been pending.
  int Delay() const { return static_cast<int>(OS::Ticks() - start_); }

 private:
  void Destroy();
  static void WeakCallback(v8::Persistent<v8::Value> object, void* data);

  PendingListNode* next_;
  Handle<Object> function_;  // Weak handle.
  int64_t start_;
};

enum SamplerState {
  IN_NON_JS_STATE = 0,
  IN_JS_STATE = 1
};

// Optimization sampler constants.
static const int kSamplerFrameCount = 2;
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
static const int kSamplerWindowSize = 16;

static const int kSamplerTicksBetweenThresholdAdjustment = 32;

static const int kSamplerThresholdInit = 3;
static const int kSamplerThresholdMin = 1;
static const int kSamplerThresholdDelta = 1;

static const int kSamplerThresholdSizeFactorInit = 3;
static const int kSamplerThresholdSizeFactorMin = 1;
static const int kSamplerThresholdSizeFactorDelta = 1;

static const int kSizeLimit = 1500;

static int sampler_threshold = kSamplerThresholdInit;
static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;

static int sampler_ticks_until_threshold_adjustment =
    kSamplerTicksBetweenThresholdAdjustment;

// The ratio of ticks spent in JS code in percent.
static Atomic32 js_ratio;

// The JSFunctions in the sampler window are not GC safe. Old-space
// pointers are not cleared during mark-sweep collection and therefore
// the window might contain stale pointers. The window is updated on
// scavenges and (parts of it) cleared on mark-sweep and
// mark-sweep-compact.
static Object* sampler_window[kSamplerWindowSize] = { NULL, };
static int sampler_window_position = 0;
static int sampler_window_weight[kSamplerWindowSize] = { 0, };

// Support for pending 'optimize soon' requests.
static PendingListNode* optimize_soon_list = NULL;

PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) {
  function_ = GlobalHandles::Create(function);
  start_ = OS::Ticks();
  GlobalHandles::MakeWeak(function_.location(), this, &WeakCallback);
}

void PendingListNode::Destroy() {
  if (!IsValid()) return;
  GlobalHandles::Destroy(function_.location());
  function_= Handle<Object>::null();
}

void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) {
  reinterpret_cast<PendingListNode*>(data)->Destroy();
}

static bool IsOptimizable(JSFunction* function) {
  Code* code = function->code();
  return code->kind() == Code::FUNCTION && code->optimizable();
}

static void Optimize(JSFunction* function, bool eager, int delay) {
  ASSERT(IsOptimizable(function));
  if (FLAG_trace_opt) {
    PrintF("[marking (%s) ", eager ? "eagerly" : "lazily");
    function->PrintName();
    PrintF(" for recompilation");
    if (delay > 0) {
      PrintF(" (delayed %0.3f ms)", static_cast<double>(delay) / 1000);
    }
    PrintF("]\n");
  }

  // The next call to the function will trigger optimization.
  function->MarkForLazyRecompilation();
}

static void AttemptOnStackReplacement(JSFunction* function) {
  // See AlwaysFullCompiler (in compiler.cc) comment on why we need
  // Debug::has_break_points().
  ASSERT(function->IsMarkedForLazyRecompilation());
  if (!FLAG_use_osr || Debug::has_break_points() || function->IsBuiltin()) {
    return;
  }

  SharedFunctionInfo* shared = function->shared();
  // If the code is not optimizable, don't try OSR.
  if (!shared->code()->optimizable()) return;

  // We are not prepared to do OSR for a function that already has an
  // allocated arguments object.  The optimized code would bypass it for
  // arguments accesses, which is unsound.  Don't try OSR.
  if (shared->scope_info()->HasArgumentsShadow()) return;

  // We're using on-stack replacement: patch the unoptimized code so that
  // any back edge in any unoptimized frame will trigger on-stack
  // replacement for that frame.
  if (FLAG_trace_osr) {
    PrintF("[patching stack checks in ");
    function->PrintName();
    PrintF(" for on-stack replacement]\n");
  }

  // Get the stack check stub code object to match against.  We aren't
  // prepared to generate it, but we don't expect to have to.
  StackCheckStub check_stub;
  Object* check_code;
  MaybeObject* maybe_check_code = check_stub.TryGetCode();
  if (maybe_check_code->ToObject(&check_code)) {
    Code* replacement_code = Builtins::builtin(Builtins::OnStackReplacement);
    Code* unoptimized_code = shared->code();
    // Iterate the unoptimized code and patch every stack check except at
    // the function entry.  This code assumes the function entry stack
    // check appears first i.e., is not deferred or otherwise reordered.
    bool first = true;
    for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask);
         !it.done();
         it.next()) {
      RelocInfo* rinfo = it.rinfo();
      if (rinfo->target_address() == Code::cast(check_code)->entry()) {
        if (first) {
          first = false;
        } else {
          Deoptimizer::PatchStackCheckCode(rinfo, replacement_code);
        }
      }
    }
  }
}

static void ClearSampleBuffer() {
  for (int i = 0; i < kSamplerWindowSize; i++) {
    sampler_window[i] = NULL;
    sampler_window_weight[i] = 0;
  }
}

static void ClearSampleBufferNewSpaceEntries() {
  for (int i = 0; i < kSamplerWindowSize; i++) {
    if (Heap::InNewSpace(sampler_window[i])) {
      sampler_window[i] = NULL;
      sampler_window_weight[i] = 0;
    }
  }
}

static int LookupSample(JSFunction* function) {
  int weight = 0;
  for (int i = 0; i < kSamplerWindowSize; i++) {
    Object* sample = sampler_window[i];
    if (sample != NULL) {
      if (function == sample) {
        weight += sampler_window_weight[i];
      }
    }
  }
  return weight;
}

static void AddSample(JSFunction* function, int weight) {
  ASSERT(IsPowerOf2(kSamplerWindowSize));
  sampler_window[sampler_window_position] = function;
  sampler_window_weight[sampler_window_position] = weight;
  sampler_window_position = (sampler_window_position + 1) &
      (kSamplerWindowSize - 1);
}

void RuntimeProfiler::OptimizeNow() {
  HandleScope scope;
  PendingListNode* current = optimize_soon_list;
  while (current != NULL) {
    PendingListNode* next = current->next();
    if (current->IsValid()) {
      Handle<JSFunction> function = current->function();
      int delay = current->Delay();
      if (IsOptimizable(*function)) {
        Optimize(*function, true, delay);
      }
    }
    delete current;
    current = next;
  }
  optimize_soon_list = NULL;

  // Run through the JavaScript frames and collect them. If we already
  // have a sample of the function, we mark it for optimizations
  // (eagerly or lazily).
  JSFunction* samples[kSamplerFrameCount];
  int sample_count = 0;
  int frame_count = 0;
  for (JavaScriptFrameIterator it;
       frame_count++ < kSamplerFrameCount && !it.done();
       it.Advance()) {
    JavaScriptFrame* frame = it.frame();
    JSFunction* function = JSFunction::cast(frame->function());

    // Adjust threshold each time we have processed
    // a certain number of ticks.
    if (sampler_ticks_until_threshold_adjustment > 0) {
      sampler_ticks_until_threshold_adjustment--;
      if (sampler_ticks_until_threshold_adjustment <= 0) {
        // If the threshold is not already at the minimum
        // modify and reset the ticks until next adjustment.
        if (sampler_threshold > kSamplerThresholdMin) {
          sampler_threshold -= kSamplerThresholdDelta;
          sampler_ticks_until_threshold_adjustment =
              kSamplerTicksBetweenThresholdAdjustment;
        }
      }
    }

    if (function->IsMarkedForLazyRecompilation()) {
      Code* unoptimized = function->shared()->code();
      int nesting = unoptimized->allow_osr_at_loop_nesting_level();
      if (nesting == 0) AttemptOnStackReplacement(function);
      int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
      unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting);
    }

    // Do not record non-optimizable functions.
    if (!IsOptimizable(function)) continue;
    samples[sample_count++] = function;

    int function_size = function->shared()->SourceSize();
    int threshold_size_factor = (function_size > kSizeLimit)
        ? sampler_threshold_size_factor
        : 1;

    int threshold = sampler_threshold * threshold_size_factor;
    int current_js_ratio = NoBarrier_Load(&js_ratio);

    // Adjust threshold depending on the ratio of time spent
    // in JS code.
    if (current_js_ratio < 20) {
      // If we spend less than 20% of the time in JS code,
      // do not optimize.
      continue;
    } else if (current_js_ratio < 75) {
      // Below 75% of time spent in JS code, only optimize very
      // frequently used functions.
      threshold *= 3;
    }

    if (LookupSample(function) >= threshold) {
      Optimize(function, false, 0);
      CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
    }
  }

  // Add the collected functions as samples. It's important not to do
  // this as part of collecting them because this will interfere with
  // the sample lookup in case of recursive functions.
  for (int i = 0; i < sample_count; i++) {
    AddSample(samples[i], kSamplerFrameWeight[i]);
  }
}

void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
  if (!IsOptimizable(function)) return;
  PendingListNode* node = new PendingListNode(function);
  node->set_next(optimize_soon_list);
  optimize_soon_list = node;
}

void RuntimeProfiler::NotifyTick() {
  StackGuard::RequestRuntimeProfilerTick();
}

void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) {
  if (is_compacting) {
    // Clear all samples before mark-sweep-compact because every
    // function might move.
    ClearSampleBuffer();
  } else {
    // Clear only new space entries on mark-sweep since none of the
    // old-space functions will move.
    ClearSampleBufferNewSpaceEntries();
  }
}

bool IsEqual(void* first, void* second) {
  return first == second;
}

void RuntimeProfiler::Setup() {
  ClearSampleBuffer();
  // If the ticker hasn't already started, make sure to do so to get
  // the ticks for the runtime profiler.
  if (IsEnabled()) Logger::EnsureTickerStarted();
}

void RuntimeProfiler::Reset() {
  sampler_threshold = kSamplerThresholdInit;
  sampler_ticks_until_threshold_adjustment =
      kSamplerTicksBetweenThresholdAdjustment;
  sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
}

void RuntimeProfiler::TearDown() {
  // Nothing to do.
}

Object** RuntimeProfiler::SamplerWindowAddress() {
  return sampler_window;
}

int RuntimeProfiler::SamplerWindowSize() {
  return kSamplerWindowSize;
}

static void AddStateSample(SamplerState current_state) {
  static const int kStateWindowSize = 128;
  static SamplerState state_window[kStateWindowSize];
  static int state_window_position = 0;
  static int state_counts[2] = { kStateWindowSize, 0 };

  SamplerState old_state = state_window[state_window_position];
  state_counts[old_state]--;
  state_window[state_window_position] = current_state;
  state_counts[current_state]++;
  ASSERT(IsPowerOf2(kStateWindowSize));
  state_window_position = (state_window_position + 1) &
      (kStateWindowSize - 1);
  NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 /
                  kStateWindowSize);
}

bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
  static const int kNonJSTicksThreshold = 100;
  // We suspend the runtime profiler thread when not running
  // JavaScript. If the CPU profiler is active we must not do this
  // because it samples both JavaScript and C++ code.
  if (RuntimeProfiler::IsEnabled() &&
      !CpuProfiler::is_profiling() &&
      !(FLAG_prof && FLAG_prof_auto)) {
    if (Top::IsInJSState()) {
      AddStateSample(IN_JS_STATE);
      non_js_ticks_ = 0;
    } else {
      AddStateSample(IN_NON_JS_STATE);
      if (non_js_ticks_ < kNonJSTicksThreshold) {
        ++non_js_ticks_;
      } else {
        if (Top::WaitForJSState()) return true;
      }
    }
  }
  return false;
}

} }  // namespace v8::internal
<|endoftext|>


<commit_before>/*
 * TCP client socket with asynchronous connect.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ConnectSocket.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "net/SocketAddress.hxx"
#include "system/fd_util.h"
#include "stopwatch.hxx"
#include "event/SocketEvent.hxx"
#include "pool.hxx"
#include "system/Error.hxx"
#include "util/Cancellable.hxx"

#include <socket/util.h>

#ifdef ENABLE_STOPWATCH
#include <socket/address.h>
#endif

#include <stdexcept>

#include <assert.h>
#include <stddef.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

void
ConnectSocketHandler::OnSocketConnectTimeout()
{
    /* default implementation falls back to OnSocketConnectError() */
    OnSocketConnectError(std::make_exception_ptr(std::runtime_error("Timeout")));
}

class ConnectSocket final : Cancellable {
    struct pool &pool;
    UniqueSocketDescriptor fd;
    SocketEvent event;

#ifdef ENABLE_STOPWATCH
    Stopwatch &stopwatch;
#endif

    ConnectSocketHandler &handler;

public:
    ConnectSocket(EventLoop &event_loop, struct pool &_pool,
                  UniqueSocketDescriptor &&_fd, unsigned timeout,
#ifdef ENABLE_STOPWATCH
                  Stopwatch &_stopwatch,
#endif
                  ConnectSocketHandler &_handler,
                  CancellablePointer &cancel_ptr)
        :pool(_pool), fd(std::move(_fd)),
         event(event_loop, fd.Get(), SocketEvent::WRITE,
               BIND_THIS_METHOD(EventCallback)),
#ifdef ENABLE_STOPWATCH
         stopwatch(_stopwatch),
#endif
         handler(_handler) {
        pool_ref(&pool);

        cancel_ptr = *this;

        const struct timeval tv = {
            .tv_sec = time_t(timeout),
            .tv_usec = 0,
        };
        event.Add(tv);
    }

    void Delete() {
        DeleteUnrefPool(pool, this);
    }

private:
    void EventCallback(unsigned events);

    /* virtual methods from class Cancellable */
    void Cancel() override;
};

/*
 * async operation
 *
 */

void
ConnectSocket::Cancel()
{
    assert(fd.IsDefined());

    event.Delete();
    Delete();
}

/*
 * libevent callback
 *
 */

inline void
ConnectSocket::EventCallback(unsigned events)
{
    if (events & SocketEvent::TIMEOUT) {
        handler.OnSocketConnectTimeout();
        Delete();
        return;
    }

    int s_err = fd.GetError();
    if (s_err == 0) {
#ifdef ENABLE_STOPWATCH
        stopwatch_event(&stopwatch, "connect");
        stopwatch_dump(&stopwatch);
#endif

        handler.OnSocketConnectSuccess(std::move(fd));
    } else {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno(s_err)));
    }

    Delete();
}

/*
 * constructor
 *
 */

void
client_socket_new(EventLoop &event_loop, struct pool &pool,
                  int domain, int type, int protocol,
                  bool ip_transparent,
                  const SocketAddress bind_address,
                  const SocketAddress address,
                  unsigned timeout,
                  ConnectSocketHandler &handler,
                  CancellablePointer &cancel_ptr)
{
    assert(!address.IsNull());

    UniqueSocketDescriptor fd;
    if (!fd.CreateNonBlock(domain, type, protocol)) {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno("Failed to create socket")));
        return;
    }

    if ((domain == PF_INET || domain == PF_INET6) && type == SOCK_STREAM &&
        !socket_set_nodelay(fd.Get(), true)) {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno()));
        return;
    }

    if (ip_transparent) {
        int on = 1;
        if (setsockopt(fd.Get(), SOL_IP, IP_TRANSPARENT, &on, sizeof on) < 0) {
            handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno("Failed to set IP_TRANSPARENT")));
            return;
        }
    }

    if (!bind_address.IsNull() && bind_address.IsDefined() &&
        !fd.Bind(bind_address)) {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno()));
        return;
    }

#ifdef ENABLE_STOPWATCH
    Stopwatch *stopwatch = stopwatch_new(&pool, address, nullptr);
#endif

    if (fd.Connect(address)) {
#ifdef ENABLE_STOPWATCH
        stopwatch_event(stopwatch, "connect");
        stopwatch_dump(stopwatch);
#endif

        handler.OnSocketConnectSuccess(std::move(fd));
    } else if (errno == EINPROGRESS) {
        NewFromPool<ConnectSocket>(pool, event_loop, pool,
                                   std::move(fd), timeout,
#ifdef ENABLE_STOPWATCH
                                   *stopwatch,
#endif
                                   handler, cancel_ptr);
    } else {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno()));
    }
}
<commit_msg>net/ConnectSocket: include cleanup<commit_after>/*
 * TCP client socket with asynchronous connect.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ConnectSocket.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "net/SocketAddress.hxx"
#include "system/fd_util.h"
#include "stopwatch.hxx"
#include "event/SocketEvent.hxx"
#include "pool.hxx"
#include "system/Error.hxx"
#include "util/Cancellable.hxx"

#include <socket/util.h>

#include <stdexcept>

#include <assert.h>
#include <stddef.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

void
ConnectSocketHandler::OnSocketConnectTimeout()
{
    /* default implementation falls back to OnSocketConnectError() */
    OnSocketConnectError(std::make_exception_ptr(std::runtime_error("Timeout")));
}

class ConnectSocket final : Cancellable {
    struct pool &pool;
    UniqueSocketDescriptor fd;
    SocketEvent event;

#ifdef ENABLE_STOPWATCH
    Stopwatch &stopwatch;
#endif

    ConnectSocketHandler &handler;

public:
    ConnectSocket(EventLoop &event_loop, struct pool &_pool,
                  UniqueSocketDescriptor &&_fd, unsigned timeout,
#ifdef ENABLE_STOPWATCH
                  Stopwatch &_stopwatch,
#endif
                  ConnectSocketHandler &_handler,
                  CancellablePointer &cancel_ptr)
        :pool(_pool), fd(std::move(_fd)),
         event(event_loop, fd.Get(), SocketEvent::WRITE,
               BIND_THIS_METHOD(EventCallback)),
#ifdef ENABLE_STOPWATCH
         stopwatch(_stopwatch),
#endif
         handler(_handler) {
        pool_ref(&pool);

        cancel_ptr = *this;

        const struct timeval tv = {
            .tv_sec = time_t(timeout),
            .tv_usec = 0,
        };
        event.Add(tv);
    }

    void Delete() {
        DeleteUnrefPool(pool, this);
    }

private:
    void EventCallback(unsigned events);

    /* virtual methods from class Cancellable */
    void Cancel() override;
};

/*
 * async operation
 *
 */

void
ConnectSocket::Cancel()
{
    assert(fd.IsDefined());

    event.Delete();
    Delete();
}

/*
 * libevent callback
 *
 */

inline void
ConnectSocket::EventCallback(unsigned events)
{
    if (events & SocketEvent::TIMEOUT) {
        handler.OnSocketConnectTimeout();
        Delete();
        return;
    }

    int s_err = fd.GetError();
    if (s_err == 0) {
#ifdef ENABLE_STOPWATCH
        stopwatch_event(&stopwatch, "connect");
        stopwatch_dump(&stopwatch);
#endif

        handler.OnSocketConnectSuccess(std::move(fd));
    } else {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno(s_err)));
    }

    Delete();
}

/*
 * constructor
 *
 */

void
client_socket_new(EventLoop &event_loop, struct pool &pool,
                  int domain, int type, int protocol,
                  bool ip_transparent,
                  const SocketAddress bind_address,
                  const SocketAddress address,
                  unsigned timeout,
                  ConnectSocketHandler &handler,
                  CancellablePointer &cancel_ptr)
{
    assert(!address.IsNull());

    UniqueSocketDescriptor fd;
    if (!fd.CreateNonBlock(domain, type, protocol)) {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno("Failed to create socket")));
        return;
    }

    if ((domain == PF_INET || domain == PF_INET6) && type == SOCK_STREAM &&
        !socket_set_nodelay(fd.Get(), true)) {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno()));
        return;
    }

    if (ip_transparent) {
        int on = 1;
        if (setsockopt(fd.Get(), SOL_IP, IP_TRANSPARENT, &on, sizeof on) < 0) {
            handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno("Failed to set IP_TRANSPARENT")));
            return;
        }
    }

    if (!bind_address.IsNull() && bind_address.IsDefined() &&
        !fd.Bind(bind_address)) {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno()));
        return;
    }

#ifdef ENABLE_STOPWATCH
    Stopwatch *stopwatch = stopwatch_new(&pool, address, nullptr);
#endif

    if (fd.Connect(address)) {
#ifdef ENABLE_STOPWATCH
        stopwatch_event(stopwatch, "connect");
        stopwatch_dump(stopwatch);
#endif

        handler.OnSocketConnectSuccess(std::move(fd));
    } else if (errno == EINPROGRESS) {
        NewFromPool<ConnectSocket>(pool, event_loop, pool,
                                   std::move(fd), timeout,
#ifdef ENABLE_STOPWATCH
                                   *stopwatch,
#endif
                                   handler, cancel_ptr);
    } else {
        handler.OnSocketConnectError(std::make_exception_ptr(MakeErrno()));
    }
}
<|endoftext|>


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

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP_
#include <com/sun/star/registry/XRegistryKey.hpp>
#endif

// @@@ Adjust multi-include-protection-ifdef and header file name.
#ifndef _MYUCP_PROVIDER_HXX
#include "myucp_provider.hxx"
#endif

using namespace com::sun::star;

//=========================================================================
static sal_Bool writeInfo( void * pRegistryKey,
                           const rtl::OUString & rImplementationName,
                              uno::Sequence< rtl::OUString > const & rServiceNames )
{
    rtl::OUString aKeyName( rtl::OUString::createFromAscii( "/" ) );
    aKeyName += rImplementationName;
    aKeyName += rtl::OUString::createFromAscii( "/UNO/SERVICES" );

    uno::Reference< registry::XRegistryKey > xKey;
    try
    {
        xKey = static_cast< registry::XRegistryKey * >(
                                    pRegistryKey )->createKey( aKeyName );
    }
    catch ( registry::InvalidRegistryException const & )
    {
    }

    if ( !xKey.is() )
        return sal_False;

    sal_Bool bSuccess = sal_True;

    for ( sal_Int32 n = 0; n < rServiceNames.getLength(); ++n )
    {
        try
        {
            xKey->createKey( rServiceNames[ n ] );
        }
        catch ( registry::InvalidRegistryException const & )
        {
            bSuccess = sal_False;
            break;
        }
    }
    return bSuccess;
}

//=========================================================================
extern "C" void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//=========================================================================
extern "C" sal_Bool SAL_CALL component_writeInfo(
    void * pServiceManager, void * pRegistryKey )
{
    return pRegistryKey &&

    //////////////////////////////////////////////////////////////////////
    // Write info into registry.
    //////////////////////////////////////////////////////////////////////

    // @@@ Adjust namespace names.
    writeInfo( pRegistryKey,
               ::myucp::ContentProvider::getImplementationName_Static(),
               ::myucp::ContentProvider::getSupportedServiceNames_Static() );
}

//=========================================================================
extern "C" void * SAL_CALL component_getFactory(
    const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
{
    void * pRet = 0;

    uno::Reference< lang::XMultiServiceFactory > xSMgr(
            reinterpret_cast< lang::XMultiServiceFactory * >( pServiceManager ) );
    uno::Reference< lang::XSingleServiceFactory > xFactory;

    //////////////////////////////////////////////////////////////////////
    // Create factory, if implementation name matches.
    //////////////////////////////////////////////////////////////////////

    // @@@ Adjust namespace names.
    if ( ::myucp::ContentProvider::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = ::myucp::ContentProvider::createServiceFactory( xSMgr );
    }

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

    if ( xFactory.is() )
    {
        xFactory->acquire();
        pRet = xFactory.get();
    }

    return pRet;
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.3.34); FILE MERGED 2006/09/01 17:56:10 kaib 1.3.34.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: myucp_services.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 17:26:30 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucbhelper.hxx"

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP_
#include <com/sun/star/registry/XRegistryKey.hpp>
#endif

// @@@ Adjust multi-include-protection-ifdef and header file name.
#ifndef _MYUCP_PROVIDER_HXX
#include "myucp_provider.hxx"
#endif

using namespace com::sun::star;

//=========================================================================
static sal_Bool writeInfo( void * pRegistryKey,
                           const rtl::OUString & rImplementationName,
                              uno::Sequence< rtl::OUString > const & rServiceNames )
{
    rtl::OUString aKeyName( rtl::OUString::createFromAscii( "/" ) );
    aKeyName += rImplementationName;
    aKeyName += rtl::OUString::createFromAscii( "/UNO/SERVICES" );

    uno::Reference< registry::XRegistryKey > xKey;
    try
    {
        xKey = static_cast< registry::XRegistryKey * >(
                                    pRegistryKey )->createKey( aKeyName );
    }
    catch ( registry::InvalidRegistryException const & )
    {
    }

    if ( !xKey.is() )
        return sal_False;

    sal_Bool bSuccess = sal_True;

    for ( sal_Int32 n = 0; n < rServiceNames.getLength(); ++n )
    {
        try
        {
            xKey->createKey( rServiceNames[ n ] );
        }
        catch ( registry::InvalidRegistryException const & )
        {
            bSuccess = sal_False;
            break;
        }
    }
    return bSuccess;
}

//=========================================================================
extern "C" void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//=========================================================================
extern "C" sal_Bool SAL_CALL component_writeInfo(
    void * pServiceManager, void * pRegistryKey )
{
    return pRegistryKey &&

    //////////////////////////////////////////////////////////////////////
    // Write info into registry.
    //////////////////////////////////////////////////////////////////////

    // @@@ Adjust namespace names.
    writeInfo( pRegistryKey,
               ::myucp::ContentProvider::getImplementationName_Static(),
               ::myucp::ContentProvider::getSupportedServiceNames_Static() );
}

//=========================================================================
extern "C" void * SAL_CALL component_getFactory(
    const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
{
    void * pRet = 0;

    uno::Reference< lang::XMultiServiceFactory > xSMgr(
            reinterpret_cast< lang::XMultiServiceFactory * >( pServiceManager ) );
    uno::Reference< lang::XSingleServiceFactory > xFactory;

    //////////////////////////////////////////////////////////////////////
    // Create factory, if implementation name matches.
    //////////////////////////////////////////////////////////////////////

    // @@@ Adjust namespace names.
    if ( ::myucp::ContentProvider::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = ::myucp::ContentProvider::createServiceFactory( xSMgr );
    }

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

    if ( xFactory.is() )
    {
        xFactory->acquire();
        pRet = xFactory.get();
    }

    return pRet;
}

<|endoftext|>


<commit_before>
#include <stdio.h>
#include "NNEngine.h"

using namespace NNEngine;

int main() {
	if ( NNWindowsApplication::GetInstance()->Init( L"Test", 1024, 768, RendererStatus::NONE ) == true )
	{
		NNWindowsApplication::GetInstance()->Run();
		NNWindowsApplication::GetInstance()->Release();
	}
	return 0;
}<commit_msg>* Create App<commit_after>
#include <stdio.h>
#include "NNEngine.h"

using namespace NNEngine;

int main() {
	if ( NNWindowsApplication::GetInstance()->Init( L"Test", 1024, 768, RendererStatus::D3D ) == true )
	{
		NNWindowsApplication::GetInstance()->Run();
		NNWindowsApplication::GetInstance()->Release();
	}
	return 0;
}<|endoftext|>


<commit_before>#include <mgf/Spectrum.hpp>
#include <mgf/Convert.hpp>
#include <mgf/Peak.hpp>

#include <mgf/defines.hpp>

#include <algorithm>

namespace mgf
{

    Spectrum::Spectrum()
    {
    }

    Spectrum::~Spectrum()
    {
        clear();
    }

    void Spectrum::push(double z,double it,char ch)
    {
        peaks.emplace_back(new Peak(z,it,ch));
    }

    void Spectrum::sort()
    {
        std::sort(this->peaks.begin(),this->peaks.end(),[](const Peak* _1 ,const Peak* _2){return _1->getMasse() < _2->getMasse();});
    }

    void Spectrum::calc_masse()
    {
        masse = mgf::Convert::mz_to_masse(header.mz,header.charge);
    }

    void Spectrum::calc_masse_peaks()
    {
        Spectrum& self = *this;

        unsigned int size =peaks.size();
        unsigned int i=0;
        while(i<size)
        {
            peaks.at(i)->calc_masse(self);
            if (peaks.at(i)->masse > masse) //supression des truc impossible à etre en lien avec le peptide
            {
                delete peaks.at(i);
                peaks.erase(peaks.begin()+i);
                --size;
            }
            else
                ++i;
        }
    }

    void Spectrum::add_specials_peaks()
    {
        /********* EXTREMITÉES ****************/
        Peak* p = new Peak(0,1,-1);
        p->masse = 0;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::DEBUT] = p;

        p = new Peak(0,1,-1);
        p->masse = this->masse;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::FIN] = p;

        /***************** H2O *******************/

        p = new Peak(0,1,-1);
        p->masse = mgf::Convert::MH2O;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::DEBUT_H2O] = p;

        p = new Peak(0,1,-1);
        p->masse = this->masse - mgf::Convert::MH2O;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::FIN_H2O] = p;
    }

    void Spectrum::prepare()
    {
        normalize_intensitee();
        calc_masse();
        calc_masse_peaks();
        add_specials_peaks();
        sort();
        peaks.shrink_to_fit();
    }

    void Spectrum::__print__(std::ostream& stream)const
    {
        stream<<"Spectrum:\n"
            <<"\tMasse: "<<masse<<"\n";
        header.__print__(stream);
        for(Peak* p :peaks)
            p->__print__(stream);
        stream<<"end Spectrum\n\n";

    }

    void Spectrum::clear()
    {
        const unsigned int size = peaks.size();
        for(unsigned int i=0;i<size;++i)
            delete peaks[i];
        peaks.clear();
    }

    void Spectrum::reset()
    {
        header.reset();
        clear();
    }

    void Spectrum::normalize_intensitee()
    {
        const unsigned int size = peaks.size();
        double max = 0;
        for(unsigned int i=0;i<size;++i)
            max = MAX(max,peaks[i]->intensity);

        for(unsigned int i=0;i<size;++i)
            peaks[i]->intensity/=max;
    };
}
<commit_msg>add comments<commit_after>#include <mgf/Spectrum.hpp>
#include <mgf/Convert.hpp>
#include <mgf/Peak.hpp>

#include <mgf/defines.hpp>

#include <algorithm>

namespace mgf
{

    Spectrum::Spectrum()
    {
    }

    Spectrum::~Spectrum()
    {
        clear();
    }

    void Spectrum::push(double z,double it,char ch)
    {
        peaks.emplace_back(new Peak(z,it,ch));
    }

    void Spectrum::sort()
    {
        std::sort(this->peaks.begin(),this->peaks.end(),[](const Peak* _1 ,const Peak* _2){return _1->getMasse() < _2->getMasse();});
    }

    void Spectrum::calc_masse()
    {
        masse = mgf::Convert::mz_to_masse(header.mz,header.charge);
    }

    void Spectrum::calc_masse_peaks()
    {
        Spectrum& self = *this;

        unsigned int size =peaks.size();
        unsigned int i=0;
        while(i<size)
        {
            peaks.at(i)->calc_masse(self);
            if (peaks.at(i)->masse > masse) //supression des truc impossible à etre en lien avec le peptide
            {
                delete peaks.at(i);
                peaks.erase(peaks.begin()+i);
                --size;
            }
            else
                ++i;
        }
    }

    void Spectrum::add_specials_peaks()
    {
        /********* EXTREMITÉES ****************/
        Peak* p = new Peak(0,1,-1);
        p->masse = 0;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::DEBUT] = p;

        p = new Peak(0,1,-1);
        p->masse = this->masse;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::FIN] = p;

        /***************** H2O *******************/

        p = new Peak(0,1,-1);
        p->masse = mgf::Convert::MH2O;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::DEBUT_H2O] = p;

        p = new Peak(0,1,-1);
        p->masse = this->masse - mgf::Convert::MH2O;
        peaks.emplace_back(p);
        special_peaks[SPECIAL::FIN_H2O] = p;
    }

    void Spectrum::prepare()
    {
        calc_masse(); // calc spectrum masse

        normalize_intensitee(); // normalize intensity of peaks (before calc_masse_peaks to make less call)
        calc_masse_peaks(); // calc peaks masse
        add_specials_peaks(); // add artificials peaks
        sort(); // sort peaks

        peaks.shrink_to_fit(); //reduce vector to minimal size
    }

    void Spectrum::__print__(std::ostream& stream)const
    {
        stream<<"Spectrum:\n"
            <<"\tMasse: "<<masse<<"\n";
        header.__print__(stream);
        for(Peak* p :peaks)
            p->__print__(stream);
        stream<<"end Spectrum\n\n";

    }

    void Spectrum::clear()
    {
        const unsigned int size = peaks.size();
        for(unsigned int i=0;i<size;++i)
            delete peaks[i];
        peaks.clear();
    }

    void Spectrum::reset()
    {
        header.reset();
        clear();
    }

    void Spectrum::normalize_intensitee()
    {
        const unsigned int size = peaks.size();
        double max = 0;
        for(unsigned int i=0;i<size;++i)
            max = MAX(max,peaks[i]->intensity);

        for(unsigned int i=0;i<size;++i)
            peaks[i]->intensity/=max;
    };
}
<|endoftext|>


<commit_before>#include "zp_data_table.h"

#include <sys/statvfs.h>
#include <glog/logging.h>

#include "zp_data_server.h"

extern ZPDataServer* zp_data_server;

Table* NewTable(const std::string &table_name, const std::string log_path, const std::string data_path) {
  Table* table = new Table(table_name, log_path, data_path);
  // TODO maybe need check
  return table;
}

//
// Table
//
Table::Table(const std::string& table_name, const std::string &log_path, const std::string &data_path)
  : table_name_(table_name),
  log_path_(log_path),
  data_path_(data_path),
  partition_cnt_(0) {
  if (log_path_.back() != '/') {
    log_path_.push_back('/');
  }
  if (data_path_.back() != '/') {
    data_path_.push_back('/');
  }
  log_path_ += table_name_ + "/";
  data_path_ += table_name_ + "/";

  slash::CreatePath(log_path_);
  slash::CreatePath(data_path_);

  pthread_rwlockattr_t attr;
  pthread_rwlockattr_init(&attr);
  pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
  pthread_rwlock_init(&partition_rw_, &attr);
}

Table::~Table() {
  {
    slash::RWLock l(&partition_rw_, true);
    for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
      delete iter->second;
    }
  }
  pthread_rwlock_destroy(&partition_rw_);
  LOG(INFO) << " Table " << table_name_ << " exit!!!";
}

bool Table::SetPartitionCount(const int count) {
  partition_cnt_ = count;
  DLOG(INFO) << " Set Table: " << table_name_ << " with " << partition_cnt_ << " partitions.";
  return true;
}

Partition* Table::GetPartition(const std::string &key) {
  slash::RWLock l(&partition_rw_, false);
  if (partition_cnt_ > 0) {
    int partition_id = std::hash<std::string>()(key) % partition_cnt_;
    return partitions_[partition_id];
  }
  return NULL;
}

Partition* Table::GetPartitionById(const int partition_id) {
  slash::RWLock l(&partition_rw_, false);
  auto it = partitions_.find(partition_id);
  //std::map<int, Partition*>::const_iterator it = partitions_.find(partition_id);
  if (it != partitions_.end()) {
    return it->second;
  }
  return NULL;
}

bool Table::UpdateOrAddPartition(const int partition_id,
    ZPMeta::PState state, const Node& master, const std::set<Node>& slaves) {
  slash::RWLock l(&partition_rw_, true);
  auto iter = partitions_.find(partition_id);
  if (iter != partitions_.end()) {
    //Exist partition: update it
    (iter->second)->Update(state, master, slaves);
    return true;
  }

  if (state != ZPMeta::PState::ACTIVE) {
    DLOG(WARNING) << "New Partition with no active state";
    return false;
  }

  // New Partition
  Partition* partition = NewPartition(table_name_,
      log_path_, data_path_, partition_id, master, slaves);
  assert(partition != NULL);

  partition->Update(ZPMeta::PState::ACTIVE, master, slaves);
  partitions_[partition_id] = partition;

  return true;
}

void Table::LeaveAllPartition() {
  slash::RWLock l(&partition_rw_, false);
  for (auto iter : partitions_) {
    (iter.second)->Leave();
  }
}

uint32_t Table::KeyToPartition(const std::string &key) {
  assert(partition_cnt_ != 0);
  return std::hash<std::string>()(key) % partition_cnt_;
}

void Table::Dump() {
  slash::RWLock l(&partition_rw_, false);
  DLOG(INFO) << "=========================";
  DLOG(INFO) << "    Table : " << table_name_;
  for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
    iter->second->Dump();
  }
  DLOG(INFO) << "--------------------------";
}

void Table::DoTimingTask() {
  slash::RWLock l(&partition_rw_, false);
  for (auto pair : partitions_) {
    pair.second->DoTimingTask();
  }
}

void Table::DumpPartitionBinlogOffsets(std::vector<PartitionBinlogOffset> &offset) {
  slash::RWLock l(&partition_rw_, false);
  PartitionBinlogOffset tboffset;
  for (auto& pair : partitions_) {
    tboffset.partition_id = pair.first;
    (pair.second)->GetBinlogOffset(&(tboffset.filenum), &(tboffset.offset));
    offset.push_back(tboffset);
  }
}

uint64_t Df(const std::string& path) {
  struct statvfs sfs;
  if (statvfs(path.data(), &sfs) != -1) {
    return (uint64_t)(sfs.f_bsize * sfs.f_blocks);
  }
  return 0LL;
}

void Table::GetCapacity(Statistic *stat) {
  stat->Reset();
  stat->table_name = table_name_;
  stat->used_disk = slash::Du(data_path_) + slash::Du(log_path_);
  // TODO anan: we will support table based disk;
  // For now, just use node's free disk instead.
  stat->free_disk = Df(data_path_);
  DLOG(INFO) << "GetCapacity for table " << table_name_ << ":";
  stat->Dump();
}
<commit_msg>fix invaild partition problem<commit_after>#include "zp_data_table.h"

#include <sys/statvfs.h>
#include <glog/logging.h>

#include "zp_data_server.h"

extern ZPDataServer* zp_data_server;

Table* NewTable(const std::string &table_name, const std::string log_path, const std::string data_path) {
  Table* table = new Table(table_name, log_path, data_path);
  // TODO maybe need check
  return table;
}

//
// Table
//
Table::Table(const std::string& table_name, const std::string &log_path, const std::string &data_path)
  : table_name_(table_name),
  log_path_(log_path),
  data_path_(data_path),
  partition_cnt_(0) {
  if (log_path_.back() != '/') {
    log_path_.push_back('/');
  }
  if (data_path_.back() != '/') {
    data_path_.push_back('/');
  }
  log_path_ += table_name_ + "/";
  data_path_ += table_name_ + "/";

  slash::CreatePath(log_path_);
  slash::CreatePath(data_path_);

  pthread_rwlockattr_t attr;
  pthread_rwlockattr_init(&attr);
  pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
  pthread_rwlock_init(&partition_rw_, &attr);
}

Table::~Table() {
  {
    slash::RWLock l(&partition_rw_, true);
    for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
      delete iter->second;
    }
  }
  pthread_rwlock_destroy(&partition_rw_);
  LOG(INFO) << " Table " << table_name_ << " exit!!!";
}

bool Table::SetPartitionCount(const int count) {
  partition_cnt_ = count;
  DLOG(INFO) << " Set Table: " << table_name_ << " with " << partition_cnt_ << " partitions.";
  return true;
}

Partition* Table::GetPartition(const std::string &key) {
  slash::RWLock l(&partition_rw_, false);
  if (partition_cnt_ > 0) {
    int partition_id = std::hash<std::string>()(key) % partition_cnt_;
    auto it = partitions_.find(partition_id);
    if (it != partitions_.end()) {
      return it->second;
    }
  }
  return NULL;
}

Partition* Table::GetPartitionById(const int partition_id) {
  slash::RWLock l(&partition_rw_, false);
  auto it = partitions_.find(partition_id);
  if (it != partitions_.end()) {
    return it->second;
  }
  return NULL;
}

bool Table::UpdateOrAddPartition(const int partition_id,
    ZPMeta::PState state, const Node& master, const std::set<Node>& slaves) {
  slash::RWLock l(&partition_rw_, true);
  auto iter = partitions_.find(partition_id);
  if (iter != partitions_.end()) {
    //Exist partition: update it
    (iter->second)->Update(state, master, slaves);
    return true;
  }

  if (state != ZPMeta::PState::ACTIVE) {
    DLOG(WARNING) << "New Partition with no active state";
    return false;
  }

  // New Partition
  Partition* partition = NewPartition(table_name_,
      log_path_, data_path_, partition_id, master, slaves);
  assert(partition != NULL);

  partition->Update(ZPMeta::PState::ACTIVE, master, slaves);
  partitions_[partition_id] = partition;

  return true;
}

void Table::LeaveAllPartition() {
  slash::RWLock l(&partition_rw_, false);
  for (auto iter : partitions_) {
    (iter.second)->Leave();
  }
}

uint32_t Table::KeyToPartition(const std::string &key) {
  assert(partition_cnt_ != 0);
  return std::hash<std::string>()(key) % partition_cnt_;
}

void Table::Dump() {
  slash::RWLock l(&partition_rw_, false);
  DLOG(INFO) << "=========================";
  DLOG(INFO) << "    Table : " << table_name_;
  for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
    iter->second->Dump();
  }
  DLOG(INFO) << "--------------------------";
}

void Table::DoTimingTask() {
  slash::RWLock l(&partition_rw_, false);
  for (auto pair : partitions_) {
    pair.second->DoTimingTask();
  }
}

void Table::DumpPartitionBinlogOffsets(std::vector<PartitionBinlogOffset> &offset) {
  slash::RWLock l(&partition_rw_, false);
  PartitionBinlogOffset tboffset;
  for (auto& pair : partitions_) {
    tboffset.partition_id = pair.first;
    (pair.second)->GetBinlogOffset(&(tboffset.filenum), &(tboffset.offset));
    offset.push_back(tboffset);
  }
}

uint64_t Df(const std::string& path) {
  struct statvfs sfs;
  if (statvfs(path.data(), &sfs) != -1) {
    return (uint64_t)(sfs.f_bsize * sfs.f_blocks);
  }
  return 0LL;
}

void Table::GetCapacity(Statistic *stat) {
  stat->Reset();
  stat->table_name = table_name_;
  stat->used_disk = slash::Du(data_path_) + slash::Du(log_path_);
  // TODO anan: we will support table based disk;
  // For now, just use node's free disk instead.
  stat->free_disk = Df(data_path_);
  DLOG(INFO) << "GetCapacity for table " << table_name_ << ":";
  stat->Dump();
}
<|endoftext|>


<commit_before>///
/// Copyright (c) 2015 Yusuke Sasaki
///
/// This software is released under the MIT License.
/// See http://opensource.org/licenses/mit-license.php or <LICENSE>.
///

#pragma once

#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>

namespace argparse {

namespace detail {
   template <typename In, typename Out, bool pass = std::is_convertible<In, Out>::value>
   struct lexical_cast_t;

   template <typename In, typename Out>
   struct lexical_cast_t<In, Out, true> {
      static Out apply(In const& val) {
         return static_cast<Out>(val);
      }
   };

   template <typename In>
   struct lexical_cast_t<In, std::string, false> {
      static std::string apply(In const& val) {
         std::ostringstream osstr;
         osstr << val;
         return osstr.str();
      }
   };

   template <typename Out>
   struct lexical_cast_t<std::string, Out, false> {
      static Out apply(std::string const& val) {
         std::istringstream isstr(val);
         Out out;
         isstr >> out;
         return out;
      }
   };

   template <typename Out, std::size_t N>
   struct lexical_cast_t<char[N], Out, false> {
      static Out apply(char const (&val)[N]) {
         std::istringstream isstr(val);
         Out out;
         isstr >> out;
         return out;
      }
   };

   template <typename Out, std::size_t N>
   struct lexical_cast_t<char const[N], Out, false> {
      static Out apply(char const (&val)[N]) {
         std::istringstream isstr(val);
         Out out;
         isstr >> out;
         return out;
      }
   };

} // namespace detail;

template <typename Out, typename In>
inline Out lexical_cast(In const& val) {
    return detail::lexical_cast_t<In, Out>::apply(val);
}

template <std::size_t... Idx>
struct index_sequence {
   using next = index_sequence<Idx..., sizeof...(Idx)>;
};

namespace detail {
   template <std::size_t Nt, std::size_t N>
   struct iota { using type = typename iota<Nt-1, N-1>::type::next; };

   template <std::size_t Nt>
   struct iota<Nt, 0> { using type = index_sequence<>; };
} // namespace detail;

template <std::size_t N>
using make_index_sequence = typename detail::iota<N, N>::type;

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
   return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// ---------

class argparse_error : public std::runtime_error {
public:
   explicit argparse_error(std::string const& msg)
      : std::runtime_error{msg} {}
};

struct argument_base {
   virtual void assign(std::string const& src) = 0;
   virtual void store_true() = 0;
   virtual bool with_value() const = 0;

   argument_base(std::string const& name, char short_name, std::string const& help)
     : name_{name}, short_name_{short_name}, help_{help} {}

   std::string const& name() const { return name_; }
   char short_name() const { return short_name_; }

private:
   std::string name_;
   char short_name_;
   std::string help_;
};

template <typename T>
struct argument_with_value : public argument_base
{
   using arg_type = T;

   argument_with_value(std::string const& name, char short_name, std::string const& help)
      : argument_base{ name, short_name, help } {}

   void assign(std::string const& src) override {
      val_ = make_unique<T>(lexical_cast<T>(src));
   }

   void store_true() override { /* do nothing. */ }
   bool with_value() const override { return true; }

   T const& get() const {
      if (!val_)
         throw argparse_error{"argument is not initialized"};
      return *val_;
   }

private:
   std::unique_ptr<T> val_;
};

struct argument_flag : public argument_base
{
   using arg_type = bool;

   argument_flag(std::string const& name, char short_name, std::string const& help)
      : argument_base{ name, short_name, help } {}

   void assign(std::string const&) override { /* do nothing. */ }
   void store_true() override { val_ = true; }
   bool with_value() const override { return false; }

   bool get() const { return val_; }

private:
   bool val_ = false;
};

template <typename... Args>
struct parser
{
   using args_type = std::tuple<typename Args::arg_type...>;

   parser(Args&&... args)
      : args_{ std::forward<Args>(args)... }
   {
      make_lookup_tables(make_index_sequence<sizeof...(Args)>());
   }

   void parse(int argc, char const* argv[]) {
      parse(std::vector<std::string>(argv, argv + argc));
   }

   void parse(std::vector<std::string> const& args) {
      try {
         if (args.empty())
            throw argparse_error{"argument must be at least one item(s)."};

         progname_ = args[0];

         for (auto it = args.begin() + 1; it != args.end(); ++it)
         {
            std::string const& arg = *it;
            if (arg.substr(0, 2) == "--") {
               // long option
               std::string::size_type pos = arg.find('=', 2);
               if (pos == std::string::npos) {
                  std::string key = arg.substr(2);
                  if (it + 1 == args.end())
                     throw argparse_error{"needs value: " + key};
                  assign(key, it);
               }
               else {
                  std::string key = arg.substr(2, pos - 2);
                  std::string val = arg.substr(pos + 1);
                  assign(key, val);
               }
            }
            else if (arg[0] == '-') {
               // short option
               char s = arg[1];
               if (it + 1 == args.end())
                  throw argparse_error{std::string("needs value: ") + s};
               assign(s, it);
            }
            else {
               // normal argument
               remains_.push_back(arg);
            }
         }

         get_values(make_index_sequence<std::tuple_size<args_type>::value>());
      }
      catch (argparse_error const& err) {
         std::cerr << "parse error: " << err.what() << std::endl;
         std::exit(1);
      }
   }

   std::string const& progname() const { return progname_; }
   args_type const& options() const { return options_; }
   std::vector<std::string> const& remains() const { return remains_; }

private:
   template <typename T>
   using lookup_table_t = std::unordered_map<T, std::reference_wrapper<argument_base>>;

   std::tuple<Args...> args_;
   lookup_table_t<std::string> lookup_;
   lookup_table_t<char> short_lookup_;

   std::string progname_;
   args_type options_;
   std::vector<std::string> remains_;

private:
   template <std::size_t I, std::size_t... Idx>
   void make_lookup_tables(index_sequence<I, Idx...>) {
      argument_base& arg = std::get<I>(args_);
      lookup_.insert({ arg.name(), arg });
      char s = arg.short_name();
      if (s != '\0')
         short_lookup_.insert({ s, arg });

      make_lookup_tables(index_sequence<Idx...>());
   }
   inline void make_lookup_tables(index_sequence<>) {}

   template <std::size_t I, std::size_t... Idx>
   void get_values(index_sequence<I, Idx...>) {
      std::get<I>(options_) = std::get<I>(args_).get();
      get_values(index_sequence<Idx...>());
   }
   inline void get_values(index_sequence<>) {}

   argument_base& get_ref(std::string const& key) {
      if (lookup_.count(key) == 0)
         throw argparse_error{"unknown option: --" + key};
      return lookup_.at(key).get();
   }

   argument_base& get_ref(char s) {
      if (short_lookup_.count(s) == 0)
         throw argparse_error{std::string("unknown option: -") + s};
      return short_lookup_.at(s).get();
   }

   void assign(std::string const& key, std::string const& val) {
      argument_base& a = get_ref(key);
      if (a.with_value()) {
         a.assign(val);
      }
      else {
         a.store_true();
      }
   }

   template <typename Key>
   void assign(Key&& key, std::vector<std::string>::const_iterator& it) {
      argument_base& a = get_ref(std::forward<Key>(key));
      if (a.with_value()) {
         ++it;
         a.assign(*it);
      }
      else {
         a.store_true();
      }
   }
};

// -----

template <typename... Args>
parser<Args...> make_parser(Args&&... args) {
   return parser<Args...>{ std::forward<Args>(args)... };
}

template <typename T>
inline argument_with_value<T> arg(std::string const& name, char short_name = '\0',
                                  std::string const& help = "") {
   return argument_with_value<T>{ name, short_name, help };
}

template <typename T>
inline argument_with_value<T> arg(std::string const& name, std::string const& help) {
   return argument_with_value<T>{ name, '\0', help };
}

inline argument_flag flag(std::string const& name, char short_name = '\0',
                          std::string const& help = "") {
   return argument_flag{ name, short_name, help };
}

inline argument_flag flag(std::string const& name, std::string const& help) {
   return argument_flag{ name, '\0', help };
}

} // namespace argparse;
<commit_msg>remove duplications of type<commit_after>///
/// Copyright (c) 2015 Yusuke Sasaki
///
/// This software is released under the MIT License.
/// See http://opensource.org/licenses/mit-license.php or <LICENSE>.
///

#pragma once

#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>

namespace argparse {

namespace detail {
   template <typename In, typename Out, bool pass = std::is_convertible<In, Out>::value>
   struct lexical_cast_t;

   template <typename In, typename Out>
   struct lexical_cast_t<In, Out, true> {
      static Out apply(In const& val) {
         return static_cast<Out>(val);
      }
   };

   template <typename In>
   struct lexical_cast_t<In, std::string, false> {
      static std::string apply(In const& val) {
         std::ostringstream osstr;
         osstr << val;
         return osstr.str();
      }
   };

   template <typename Out>
   struct lexical_cast_t<std::string, Out, false> {
      static Out apply(std::string const& val) {
         std::istringstream isstr(val);
         Out out;
         isstr >> out;
         return out;
      }
   };

   template <typename Out, std::size_t N>
   struct lexical_cast_t<char[N], Out, false> {
      static Out apply(char const (&val)[N]) {
         std::istringstream isstr(val);
         Out out;
         isstr >> out;
         return out;
      }
   };

   template <typename Out, std::size_t N>
   struct lexical_cast_t<char const[N], Out, false> {
      static Out apply(char const (&val)[N]) {
         std::istringstream isstr(val);
         Out out;
         isstr >> out;
         return out;
      }
   };

} // namespace detail;

template <typename Out, typename In>
inline Out lexical_cast(In const& val) {
    return detail::lexical_cast_t<In, Out>::apply(val);
}

template <std::size_t... Idx>
struct index_sequence {
   using next = index_sequence<Idx..., sizeof...(Idx)>;
};

namespace detail {
   template <std::size_t Nt, std::size_t N>
   struct iota { using type = typename iota<Nt-1, N-1>::type::next; };

   template <std::size_t Nt>
   struct iota<Nt, 0> { using type = index_sequence<>; };
} // namespace detail;

template <std::size_t N>
using make_index_sequence = typename detail::iota<N, N>::type;

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
   return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// ---------

class argparse_error : public std::runtime_error {
public:
   explicit argparse_error(std::string const& msg)
      : std::runtime_error{msg} {}
};

struct argument_base {
   virtual void assign(std::string const& src) = 0;
   virtual void store_true() = 0;
   virtual bool with_value() const = 0;

   argument_base(std::string const& name, char short_name, std::string const& help)
     : name_{name}, short_name_{short_name}, help_{help} {}

   std::string const& name() const { return name_; }
   char short_name() const { return short_name_; }

private:
   std::string name_;
   char short_name_;
   std::string help_;
};

template <typename T>
struct argument_with_value : public argument_base
{
   using arg_type = T;

   argument_with_value(std::string const& name, char short_name, std::string const& help)
      : argument_base{ name, short_name, help } {}

   void assign(std::string const& src) override {
      val_ = make_unique<T>(lexical_cast<T>(src));
   }

   void store_true() override { /* do nothing. */ }
   bool with_value() const override { return true; }

   T const& get() const {
      if (!val_)
         throw argparse_error{"argument is not initialized"};
      return *val_;
   }

private:
   std::unique_ptr<T> val_;
};

struct argument_flag : public argument_base
{
   using arg_type = bool;

   argument_flag(std::string const& name, char short_name, std::string const& help)
      : argument_base{ name, short_name, help } {}

   void assign(std::string const&) override { /* do nothing. */ }
   void store_true() override { val_ = true; }
   bool with_value() const override { return false; }

   bool get() const { return val_; }

private:
   bool val_ = false;
};

template <typename... Args>
struct parser
{
   using args_type = std::tuple<typename Args::arg_type...>;

   parser(Args&&... args)
      : args_{ std::forward<Args>(args)... }
   {
      make_lookup_tables(make_index_sequence<sizeof...(Args)>());
   }

   void parse(int argc, char const* argv[]) {
      parse(std::vector<std::string>(argv, argv + argc));
   }

   void parse(std::vector<std::string> const& args) {
      try {
         if (args.empty())
            throw argparse_error{"argument must be at least one item(s)."};

         progname_ = args[0];

         for (auto it = args.begin() + 1; it != args.end(); ++it)
         {
            std::string const& arg = *it;
            if (arg.substr(0, 2) == "--") {
               // long option
               std::string::size_type pos = arg.find('=', 2);
               if (pos == std::string::npos) {
                  std::string key = arg.substr(2);
                  if (it + 1 == args.end())
                     throw argparse_error{"needs value: " + key};
                  assign(key, it);
               }
               else {
                  std::string key = arg.substr(2, pos - 2);
                  std::string val = arg.substr(pos + 1);
                  assign(key, val);
               }
            }
            else if (arg[0] == '-') {
               // short option
               char s = arg[1];
               if (it + 1 == args.end())
                  throw argparse_error{std::string("needs value: ") + s};
               assign(s, it);
            }
            else {
               // normal argument
               remains_.push_back(arg);
            }
         }

         get_values(make_index_sequence<std::tuple_size<args_type>::value>());
      }
      catch (argparse_error const& err) {
         std::cerr << "parse error: " << err.what() << std::endl;
         std::exit(1);
      }
   }

   std::string const& progname() const { return progname_; }
   args_type const& options() const { return options_; }
   std::vector<std::string> const& remains() const { return remains_; }

private:
   template <typename T>
   using lookup_table_t = std::unordered_map<T, std::reference_wrapper<argument_base>>;

   std::tuple<Args...> args_;
   lookup_table_t<std::string> lookup_;
   lookup_table_t<char> short_lookup_;

   std::string progname_;
   args_type options_;
   std::vector<std::string> remains_;

private:
   template <std::size_t I, std::size_t... Idx>
   void make_lookup_tables(index_sequence<I, Idx...>) {
      argument_base& arg = std::get<I>(args_);
      lookup_.insert({ arg.name(), arg });
      char s = arg.short_name();
      if (s != '\0')
         short_lookup_.insert({ s, arg });

      make_lookup_tables(index_sequence<Idx...>());
   }
   inline void make_lookup_tables(index_sequence<>) {}

   template <std::size_t I, std::size_t... Idx>
   void get_values(index_sequence<I, Idx...>) {
      std::get<I>(options_) = std::get<I>(args_).get();
      get_values(index_sequence<Idx...>());
   }
   inline void get_values(index_sequence<>) {}

   argument_base& get_ref(std::string const& key) {
      if (lookup_.count(key) == 0)
         throw argparse_error{"unknown option: --" + key};
      return lookup_.at(key).get();
   }

   argument_base& get_ref(char s) {
      if (short_lookup_.count(s) == 0)
         throw argparse_error{std::string("unknown option: -") + s};
      return short_lookup_.at(s).get();
   }

   void assign(std::string const& key, std::string const& val) {
      argument_base& a = get_ref(key);
      if (a.with_value()) {
         a.assign(val);
      }
      else {
         a.store_true();
      }
   }

   template <typename Key>
   void assign(Key&& key, std::vector<std::string>::const_iterator& it) {
      argument_base& a = get_ref(std::forward<Key>(key));
      if (a.with_value()) {
         ++it;
         a.assign(*it);
      }
      else {
         a.store_true();
      }
   }
};

// -----

template <typename... Args>
inline parser<Args...> make_parser(Args&&... args) {
   return { std::forward<Args>(args)... };
}

template <typename T>
inline argument_with_value<T> arg(std::string const& name, char short_name = '\0',
                                  std::string const& help = "") {
   return { name, short_name, help };
}

template <typename T>
inline argument_with_value<T> arg(std::string const& name, std::string const& help) {
   return { name, '\0', help };
}

inline argument_flag flag(std::string const& name, char short_name = '\0',
                          std::string const& help = "") {
   return { name, short_name, help };
}

inline argument_flag flag(std::string const& name, std::string const& help) {
   return { name, '\0', help };
}

} // namespace argparse;
<|endoftext|>