<commit_before>/*
 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <assert.h>
#include <windows.h>
#include <exception>
#include <stdexcept>

#include "native_client/src/shared/platform/nacl_log.h"
#include "native_client/src/trusted/gdb_rsp/abi.h"
#include "native_client/src/trusted/port/mutex.h"
#include "native_client/src/trusted/port/thread.h"
#include "native_client/src/trusted/service_runtime/nacl_signal.h"

/*
 * Define the OS specific portions of IThread interface.
 */

namespace {

const int kX86TrapFlag = 1 << 8;

const int kDBG_PRINTEXCEPTION_C = 0x40010006;

}  // namespace

namespace port {

static IThread::CatchFunc_t s_CatchFunc = NULL;
static void* s_CatchCookie = NULL;
static PVOID s_OldCatch = NULL;

enum PosixSignals {
  SIGINT  = 2,
  SIGQUIT = 3,
  SIGILL  = 4,
  SIGTRACE= 5,
  SIGBUS  = 7,
  SIGFPE  = 8,
  SIGKILL = 9,
  SIGSEGV = 11,
  SIGSTKFLT = 16,
};

static IMutex* ThreadGetLock() {
  static IMutex* mutex_ = IMutex::Allocate();
  return mutex_;
}

static IThread::ThreadMap_t *ThreadGetMap() {
  static IThread::ThreadMap_t* map_ = new IThread::ThreadMap_t;
  return map_;
}

static int8_t ExceptionToSignal(int ex) {
  switch (ex) {
    case EXCEPTION_GUARD_PAGE:
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
    case EXCEPTION_DATATYPE_MISALIGNMENT:
    case EXCEPTION_ACCESS_VIOLATION:
    case EXCEPTION_IN_PAGE_ERROR:
      return SIGSEGV;

    case EXCEPTION_BREAKPOINT:
    case EXCEPTION_SINGLE_STEP:
      return SIGTRACE;

    case EXCEPTION_FLT_DENORMAL_OPERAND:
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
    case EXCEPTION_FLT_INEXACT_RESULT:
    case EXCEPTION_FLT_INVALID_OPERATION:
    case EXCEPTION_FLT_OVERFLOW:
    case EXCEPTION_FLT_STACK_CHECK:
    case EXCEPTION_FLT_UNDERFLOW:
      return SIGFPE;

    case EXCEPTION_INT_DIVIDE_BY_ZERO:
    case EXCEPTION_INT_OVERFLOW:
    case EXCEPTION_ILLEGAL_INSTRUCTION:
    case EXCEPTION_PRIV_INSTRUCTION:
      return SIGILL;

    case EXCEPTION_STACK_OVERFLOW:
      return SIGSTKFLT;

    case CONTROL_C_EXIT:
      return SIGQUIT;

    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
    case EXCEPTION_INVALID_DISPOSITION:
    case EXCEPTION_INVALID_HANDLE:
      return SIGILL;
  }
  return SIGILL;
}

class Thread : public IThread {
 public:
  Thread(uint32_t id, struct NaClAppThread *natp)
      : ref_(1), id_(id), handle_(NULL), natp_(natp), state_(RUNNING) {
    handle_ = OpenThread(THREAD_ALL_ACCESS, false, id);
    if (NULL == handle_) state_ = DEAD;
  }

  ~Thread() {
    if (NULL == handle_) return;

    // This should always succeed, so ignore the return.
    (void) CloseHandle(handle_);
  }

  uint32_t GetId() {
    return id_;
  }

  State GetState() {
    return state_;
  }

  virtual bool Suspend() {
    MutexLock lock(ThreadGetLock());
    if (state_ != RUNNING) return false;

    // Attempt to suspend the thread
    DWORD count = SuspendThread(handle_);

    CONTEXT win_context;
    win_context.ContextFlags = CONTEXT_ALL;
    if (!GetThreadContext(handle_, &win_context)) {
      NaClLog(LOG_FATAL, "Thread::Suspend: GetThreadContext failed\n");
    }
    NaClSignalContextFromHandler(&context_, &win_context);

    if (count != -1) {
      state_ = SUSPENDED;
      return true;
    }

    return false;
  }

  virtual bool Resume() {
    MutexLock lock(ThreadGetLock());
    if (state_ != SUSPENDED) return false;

    CONTEXT win_context;
    win_context.ContextFlags = CONTEXT_ALL;
    NaClSignalContextToHandler(&win_context, &context_);
    if (!SetThreadContext(handle_, &win_context)) {
      NaClLog(LOG_FATAL, "Thread::Resume: SetThreadContext failed\n");
    }

    // Attempt to resume the thread
    if (ResumeThread(handle_) != -1) {
      state_ = RUNNING;
      return true;
    }

    return false;
  }

  virtual bool SetStep(bool on) {
#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
    if (on) {
      context_.flags |= kX86TrapFlag;
    } else {
      context_.flags &= ~kX86TrapFlag;
    }
    return true;
#else
    // TODO(mseaborn): Implement for ARM.
    UNREFERENCED_PARAMETER(on);
    return false;
#endif
  }

  virtual bool GetRegister(uint32_t index, void *dst, uint32_t len) {
    const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
    const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
    memcpy(dst, (char *) &context_ + reg->offset_, len);
    return false;
  }

  virtual bool SetRegister(uint32_t index, void *src, uint32_t len) {
    const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
    const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
    memcpy((char *) &context_ + reg->offset_, src, len);
    return false;
  }

  virtual void* GetContext() { return &context_; }

  static LONG NTAPI ExceptionCatch(PEXCEPTION_POINTERS ep) {
    uint32_t id = static_cast<uint32_t>(GetCurrentThreadId());
    Thread* thread = static_cast<Thread*>(Acquire(id));

    // This 2 lines is a fix for the bug:
    // 366: Linux GDB doesn't work for Chrome
    // http://code.google.com/p/nativeclient/issues/detail?id=366
    // When debug stub thread opens socket to listen (for RSP debugger),
    // it triggers some component to send DBG_PRINTEXCEPTION(with string
    // "swi_lsp: non-browser app; disable"), then VEH handler goes into wait
    // for debugger to resolve exception.
    // But debugger is not connected, and debug thread is not listening on
    // connection! It get stuck.
    // Ignoring this exception - for now - helps debug stub start on chrome.
    // Now it can listen on RSP connection and can get debugger connected etc.
    if (kDBG_PRINTEXCEPTION_C == ep->ExceptionRecord->ExceptionCode) {
      return EXCEPTION_CONTINUE_EXECUTION;
    }

    // If we are not tracking this thread, then ignore it
    if (NULL == thread) return EXCEPTION_CONTINUE_SEARCH;

    State old_state = thread->state_;
    thread->state_ = SIGNALED;
    int8_t sig = ExceptionToSignal(ep->ExceptionRecord->ExceptionCode);

    // Handle EXCEPTION_BREAKPOINT SEH/VEH handler special case:
    // Here instruction pointer from the CONTEXT structure points to the int3
    // instruction, not after the int3 instruction.
    // This is different from the hardware context, and (thus) different from
    // the context obtained via GetThreadContext on Windows and from signal
    // handler context on Linux.
    // See http://code.google.com/p/nativeclient/issues/detail?id=1730.
    // We adjust instruction pointer to match the hardware.
    if (ep->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) {
#if NACL_BUILD_SUBARCH == 64
      ep->ContextRecord->Rip += 1;
#else
      ep->ContextRecord->Eip += 1;
#endif
    }

    struct NaClSignalContext *context =
        (struct NaClSignalContext *)thread->GetContext();
    NaClSignalContextFromHandler(context, ep->ContextRecord);
    if (NULL != s_CatchFunc) s_CatchFunc(id, sig, s_CatchCookie);
    NaClSignalContextToHandler(ep->ContextRecord, context);

    thread->state_ = old_state;
    Release(thread);
    return EXCEPTION_CONTINUE_EXECUTION;
  }

 private:
  uint32_t ref_;
  uint32_t id_;
  struct NaClAppThread *natp_;
  State  state_;
  HANDLE handle_;
  struct NaClSignalContext context_;

  friend class IThread;
};

IThread* IThread::Create(uint32_t id, struct NaClAppThread* natp) {
  MutexLock lock(ThreadGetLock());
  Thread* thread;
  ThreadMap_t &map = *ThreadGetMap();

  if (map.count(id)) {
    NaClLog(LOG_FATAL, "IThread::Create: thread 0x%x already exists\n", id);
  }

  thread = new Thread(id, natp);
  if (NULL == thread->handle_) {
    delete thread;
    return NULL;
  }

  map[id] = thread;
  return thread;
}

IThread* IThread::Acquire(uint32_t id) {
  MutexLock lock(ThreadGetLock());
  Thread* thread;
  ThreadMap_t &map = *ThreadGetMap();

  if (map.count(id) == 0) {
    NaClLog(LOG_FATAL, "IThread::Acquire: thread 0x%x does not exist\n", id);
  }

  thread = static_cast<Thread*>(map[id]);
  thread->ref_++;
  return thread;
}

void IThread::Release(IThread *ithread) {
  MutexLock lock(ThreadGetLock());
  Thread* thread = static_cast<Thread*>(ithread);
  thread->ref_--;

  if (thread->ref_ == 0) {
    ThreadGetMap()->erase(thread->id_);
    delete static_cast<IThread*>(thread);
  }
}

void IThread::SetExceptionCatch(IThread::CatchFunc_t func, void *cookie) {
  MutexLock lock(ThreadGetLock());

  // Remove our old catch if there is one, this allows us to add again
  if (NULL != s_OldCatch) RemoveVectoredExceptionHandler(s_OldCatch);

  // Add the new one, at the front of the list
  s_OldCatch = AddVectoredExceptionHandler(1, Thread::ExceptionCatch);
  s_CatchFunc = func;
  s_CatchCookie = cookie;
}

}  // End of port namespace

<commit_msg>Debug stub: use NaClThread::tid handle for Win threads<commit_after>/*
 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <assert.h>
#include <windows.h>
#include <exception>
#include <stdexcept>

#include "native_client/src/shared/platform/nacl_log.h"
#include "native_client/src/trusted/gdb_rsp/abi.h"
#include "native_client/src/trusted/port/mutex.h"
#include "native_client/src/trusted/port/thread.h"
#include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
#include "native_client/src/trusted/service_runtime/nacl_signal.h"

/*
 * Define the OS specific portions of IThread interface.
 */

namespace {

const int kX86TrapFlag = 1 << 8;

const int kDBG_PRINTEXCEPTION_C = 0x40010006;

}  // namespace

namespace port {

static IThread::CatchFunc_t s_CatchFunc = NULL;
static void* s_CatchCookie = NULL;
static PVOID s_OldCatch = NULL;

enum PosixSignals {
  SIGINT  = 2,
  SIGQUIT = 3,
  SIGILL  = 4,
  SIGTRACE= 5,
  SIGBUS  = 7,
  SIGFPE  = 8,
  SIGKILL = 9,
  SIGSEGV = 11,
  SIGSTKFLT = 16,
};

static IMutex* ThreadGetLock() {
  static IMutex* mutex_ = IMutex::Allocate();
  return mutex_;
}

static IThread::ThreadMap_t *ThreadGetMap() {
  static IThread::ThreadMap_t* map_ = new IThread::ThreadMap_t;
  return map_;
}

static int8_t ExceptionToSignal(int ex) {
  switch (ex) {
    case EXCEPTION_GUARD_PAGE:
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
    case EXCEPTION_DATATYPE_MISALIGNMENT:
    case EXCEPTION_ACCESS_VIOLATION:
    case EXCEPTION_IN_PAGE_ERROR:
      return SIGSEGV;

    case EXCEPTION_BREAKPOINT:
    case EXCEPTION_SINGLE_STEP:
      return SIGTRACE;

    case EXCEPTION_FLT_DENORMAL_OPERAND:
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
    case EXCEPTION_FLT_INEXACT_RESULT:
    case EXCEPTION_FLT_INVALID_OPERATION:
    case EXCEPTION_FLT_OVERFLOW:
    case EXCEPTION_FLT_STACK_CHECK:
    case EXCEPTION_FLT_UNDERFLOW:
      return SIGFPE;

    case EXCEPTION_INT_DIVIDE_BY_ZERO:
    case EXCEPTION_INT_OVERFLOW:
    case EXCEPTION_ILLEGAL_INSTRUCTION:
    case EXCEPTION_PRIV_INSTRUCTION:
      return SIGILL;

    case EXCEPTION_STACK_OVERFLOW:
      return SIGSTKFLT;

    case CONTROL_C_EXIT:
      return SIGQUIT;

    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
    case EXCEPTION_INVALID_DISPOSITION:
    case EXCEPTION_INVALID_HANDLE:
      return SIGILL;
  }
  return SIGILL;
}

class Thread : public IThread {
 public:
  Thread(uint32_t id, struct NaClAppThread *natp)
      : ref_(1), id_(id), natp_(natp), state_(RUNNING) {}

  ~Thread() {}

  uint32_t GetId() {
    return id_;
  }

  State GetState() {
    return state_;
  }

  virtual bool Suspend() {
    MutexLock lock(ThreadGetLock());
    if (state_ != RUNNING) return false;

    // Attempt to suspend the thread
    DWORD count = SuspendThread(natp_->thread.tid);

    CONTEXT win_context;
    win_context.ContextFlags = CONTEXT_ALL;
    if (!GetThreadContext(natp_->thread.tid, &win_context)) {
      NaClLog(LOG_FATAL, "Thread::Suspend: GetThreadContext failed\n");
    }
    NaClSignalContextFromHandler(&context_, &win_context);

    if (count != -1) {
      state_ = SUSPENDED;
      return true;
    }

    return false;
  }

  virtual bool Resume() {
    MutexLock lock(ThreadGetLock());
    if (state_ != SUSPENDED) return false;

    CONTEXT win_context;
    win_context.ContextFlags = CONTEXT_ALL;
    NaClSignalContextToHandler(&win_context, &context_);
    if (!SetThreadContext(natp_->thread.tid, &win_context)) {
      NaClLog(LOG_FATAL, "Thread::Resume: SetThreadContext failed\n");
    }

    // Attempt to resume the thread
    if (ResumeThread(natp_->thread.tid) != -1) {
      state_ = RUNNING;
      return true;
    }

    return false;
  }

  virtual bool SetStep(bool on) {
#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
    if (on) {
      context_.flags |= kX86TrapFlag;
    } else {
      context_.flags &= ~kX86TrapFlag;
    }
    return true;
#else
    // TODO(mseaborn): Implement for ARM.
    UNREFERENCED_PARAMETER(on);
    return false;
#endif
  }

  virtual bool GetRegister(uint32_t index, void *dst, uint32_t len) {
    const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
    const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
    memcpy(dst, (char *) &context_ + reg->offset_, len);
    return false;
  }

  virtual bool SetRegister(uint32_t index, void *src, uint32_t len) {
    const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
    const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
    memcpy((char *) &context_ + reg->offset_, src, len);
    return false;
  }

  virtual void* GetContext() { return &context_; }

  static LONG NTAPI ExceptionCatch(PEXCEPTION_POINTERS ep) {
    uint32_t id = static_cast<uint32_t>(GetCurrentThreadId());
    Thread* thread = static_cast<Thread*>(Acquire(id));

    // This 2 lines is a fix for the bug:
    // 366: Linux GDB doesn't work for Chrome
    // http://code.google.com/p/nativeclient/issues/detail?id=366
    // When debug stub thread opens socket to listen (for RSP debugger),
    // it triggers some component to send DBG_PRINTEXCEPTION(with string
    // "swi_lsp: non-browser app; disable"), then VEH handler goes into wait
    // for debugger to resolve exception.
    // But debugger is not connected, and debug thread is not listening on
    // connection! It get stuck.
    // Ignoring this exception - for now - helps debug stub start on chrome.
    // Now it can listen on RSP connection and can get debugger connected etc.
    if (kDBG_PRINTEXCEPTION_C == ep->ExceptionRecord->ExceptionCode) {
      return EXCEPTION_CONTINUE_EXECUTION;
    }

    // If we are not tracking this thread, then ignore it
    if (NULL == thread) return EXCEPTION_CONTINUE_SEARCH;

    State old_state = thread->state_;
    thread->state_ = SIGNALED;
    int8_t sig = ExceptionToSignal(ep->ExceptionRecord->ExceptionCode);

    // Handle EXCEPTION_BREAKPOINT SEH/VEH handler special case:
    // Here instruction pointer from the CONTEXT structure points to the int3
    // instruction, not after the int3 instruction.
    // This is different from the hardware context, and (thus) different from
    // the context obtained via GetThreadContext on Windows and from signal
    // handler context on Linux.
    // See http://code.google.com/p/nativeclient/issues/detail?id=1730.
    // We adjust instruction pointer to match the hardware.
    if (ep->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) {
#if NACL_BUILD_SUBARCH == 64
      ep->ContextRecord->Rip += 1;
#else
      ep->ContextRecord->Eip += 1;
#endif
    }

    struct NaClSignalContext *context =
        (struct NaClSignalContext *)thread->GetContext();
    NaClSignalContextFromHandler(context, ep->ContextRecord);
    if (NULL != s_CatchFunc) s_CatchFunc(id, sig, s_CatchCookie);
    NaClSignalContextToHandler(ep->ContextRecord, context);

    thread->state_ = old_state;
    Release(thread);
    return EXCEPTION_CONTINUE_EXECUTION;
  }

 private:
  uint32_t ref_;
  uint32_t id_;
  struct NaClAppThread *natp_;
  State  state_;
  struct NaClSignalContext context_;

  friend class IThread;
};

IThread* IThread::Create(uint32_t id, struct NaClAppThread* natp) {
  MutexLock lock(ThreadGetLock());
  Thread* thread;
  ThreadMap_t &map = *ThreadGetMap();

  if (map.count(id)) {
    NaClLog(LOG_FATAL, "IThread::Create: thread 0x%x already exists\n", id);
  }

  thread = new Thread(id, natp);
  map[id] = thread;
  return thread;
}

IThread* IThread::Acquire(uint32_t id) {
  MutexLock lock(ThreadGetLock());
  Thread* thread;
  ThreadMap_t &map = *ThreadGetMap();

  if (map.count(id) == 0) {
    NaClLog(LOG_FATAL, "IThread::Acquire: thread 0x%x does not exist\n", id);
  }

  thread = static_cast<Thread*>(map[id]);
  thread->ref_++;
  return thread;
}

void IThread::Release(IThread *ithread) {
  MutexLock lock(ThreadGetLock());
  Thread* thread = static_cast<Thread*>(ithread);
  thread->ref_--;

  if (thread->ref_ == 0) {
    ThreadGetMap()->erase(thread->id_);
    delete static_cast<IThread*>(thread);
  }
}

void IThread::SetExceptionCatch(IThread::CatchFunc_t func, void *cookie) {
  MutexLock lock(ThreadGetLock());

  // Remove our old catch if there is one, this allows us to add again
  if (NULL != s_OldCatch) RemoveVectoredExceptionHandler(s_OldCatch);

  // Add the new one, at the front of the list
  s_OldCatch = AddVectoredExceptionHandler(1, Thread::ExceptionCatch);
  s_CatchFunc = func;
  s_CatchCookie = cookie;
}

}  // End of port namespace

<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_PROB_NEG_BINOMIAL_LPMF_HPP
#define STAN_MATH_PRIM_PROB_NEG_BINOMIAL_LPMF_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/binomial_coefficient_log.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/digamma.hpp>
#include <stan/math/prim/fun/lgamma.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/max_size.hpp>
#include <stan/math/prim/fun/multiply_log.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/size_zero.hpp>
#include <stan/math/prim/fun/value_of.hpp>
#include <stan/math/prim/functor/operands_and_partials.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
// Exposing to let me use in tests
// The current tests fail for 1e8 and pass for 1e9, so setting to 1e10
constexpr double neg_binomial_alpha_cutoff = 1e10;
}  // namespace internal

// NegBinomial(n|alpha, beta)  [alpha > 0;  beta > 0;  n >= 0]
template <bool propto, typename T_n, typename T_shape, typename T_inv_scale>
return_type_t<T_shape, T_inv_scale> neg_binomial_lpmf(const T_n& n,
                                                      const T_shape& alpha,
                                                      const T_inv_scale& beta) {
  using T_partials_return = partials_return_t<T_n, T_shape, T_inv_scale>;
  using std::log;
  static const char* function = "neg_binomial_lpmf";
  check_nonnegative(function, "Failures variable", n);
  check_positive_finite(function, "Shape parameter", alpha);
  check_positive_finite(function, "Inverse scale parameter", beta);
  check_consistent_sizes(function, "Failures variable", n, "Shape parameter",
                         alpha, "Inverse scale parameter", beta);

  if (size_zero(n, alpha, beta)) {
    return 0.0;
  }
  if (!include_summand<propto, T_shape, T_inv_scale>::value) {
    return 0.0;
  }

  T_partials_return logp(0.0);
  operands_and_partials<T_shape, T_inv_scale> ops_partials(alpha, beta);

  scalar_seq_view<T_n> n_vec(n);
  scalar_seq_view<T_shape> alpha_vec(alpha);
  scalar_seq_view<T_inv_scale> beta_vec(beta);
  size_t size_alpha = stan::math::size(alpha);
  size_t size_beta = stan::math::size(beta);
  size_t size_alpha_beta = max_size(alpha, beta);
  size_t max_size_seq_view = max_size(n, alpha, beta);

  VectorBuilder<!is_constant_all<T_shape>::value, T_partials_return, T_shape>
      digamma_alpha(size_alpha);
  if (!is_constant_all<T_shape>::value) {
    for (size_t i = 0; i < size_alpha; ++i) {
      digamma_alpha[i] = digamma(value_of(alpha_vec[i]));
    }
  }

  VectorBuilder<true, T_partials_return, T_inv_scale> log1p_inv_beta(size_beta);
  VectorBuilder<true, T_partials_return, T_inv_scale> log1p_beta(size_beta);
  for (size_t i = 0; i < size_beta; ++i) {
    const T_partials_return beta_dbl = value_of(beta_vec[i]);
    log1p_inv_beta[i] = log1p(inv(beta_dbl));
    log1p_beta[i] = log1p(beta_dbl);
  }

  VectorBuilder<!is_constant_all<T_inv_scale>::value, T_partials_return,
                T_shape, T_inv_scale>
      lambda_m_alpha_over_1p_beta(size_alpha_beta);
  if (!is_constant_all<T_inv_scale>::value) {
    for (size_t i = 0; i < size_alpha_beta; ++i) {
      const T_partials_return alpha_dbl = value_of(alpha_vec[i]);
      const T_partials_return beta_dbl = value_of(beta_vec[i]);
      lambda_m_alpha_over_1p_beta[i]
          = alpha_dbl / beta_dbl - alpha_dbl / (1 + beta_dbl);
    }
  }

  for (size_t i = 0; i < max_size_seq_view; i++) {
    const T_partials_return alpha_dbl = value_of(alpha_vec[i]);
    const T_partials_return beta_dbl = value_of(beta_vec[i]);

    if (include_summand<propto, T_shape>::value) {
      if (n_vec[i] != 0) {
        logp += binomial_coefficient_log(n_vec[i] + alpha_dbl - 1.0,
                                         alpha_dbl - 1.0);
      }
    }
    logp += -alpha_dbl * log1p_inv_beta[i] - n_vec[i] * log1p_beta[i];

    if (!is_constant_all<T_shape>::value) {
      ops_partials.edge1_.partials_[i] += digamma(alpha_dbl + n_vec[i])
                                          - digamma_alpha[i]
                                          - log1p_inv_beta[i];
    }
    if (!is_constant_all<T_inv_scale>::value) {
      ops_partials.edge2_.partials_[i]
          += lambda_m_alpha_over_1p_beta[i] - n_vec[i] / (beta_dbl + 1.0);
    }
  }

  return ops_partials.build(logp);
}

template <typename T_n, typename T_shape, typename T_inv_scale>
inline return_type_t<T_shape, T_inv_scale> neg_binomial_lpmf(
    const T_n& n, const T_shape& alpha, const T_inv_scale& beta) {
  return neg_binomial_lpmf<false>(n, alpha, beta);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Pulled alpha/beta values into their own containers (Issue #1763)<commit_after>#ifndef STAN_MATH_PRIM_PROB_NEG_BINOMIAL_LPMF_HPP
#define STAN_MATH_PRIM_PROB_NEG_BINOMIAL_LPMF_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/binomial_coefficient_log.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/digamma.hpp>
#include <stan/math/prim/fun/lgamma.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/max_size.hpp>
#include <stan/math/prim/fun/multiply_log.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/size_zero.hpp>
#include <stan/math/prim/fun/value_of.hpp>
#include <stan/math/prim/functor/operands_and_partials.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
// Exposing to let me use in tests
// The current tests fail for 1e8 and pass for 1e9, so setting to 1e10
constexpr double neg_binomial_alpha_cutoff = 1e10;
}  // namespace internal

// NegBinomial(n|alpha, beta)  [alpha > 0;  beta > 0;  n >= 0]
template <bool propto, typename T_n, typename T_shape, typename T_inv_scale>
return_type_t<T_shape, T_inv_scale> neg_binomial_lpmf(const T_n& n,
                                                      const T_shape& alpha,
                                                      const T_inv_scale& beta) {
  using T_partials_return = partials_return_t<T_n, T_shape, T_inv_scale>;
  using std::log;
  static const char* function = "neg_binomial_lpmf";
  check_nonnegative(function, "Failures variable", n);
  check_positive_finite(function, "Shape parameter", alpha);
  check_positive_finite(function, "Inverse scale parameter", beta);
  check_consistent_sizes(function, "Failures variable", n, "Shape parameter",
                         alpha, "Inverse scale parameter", beta);

  if (size_zero(n, alpha, beta)) {
    return 0.0;
  }
  if (!include_summand<propto, T_shape, T_inv_scale>::value) {
    return 0.0;
  }

  T_partials_return logp(0.0);
  operands_and_partials<T_shape, T_inv_scale> ops_partials(alpha, beta);

  scalar_seq_view<T_n> n_vec(n);
  scalar_seq_view<T_shape> alpha_vec(alpha);
  scalar_seq_view<T_inv_scale> beta_vec(beta);
  size_t size_alpha = stan::math::size(alpha);
  size_t size_beta = stan::math::size(beta);
  size_t size_alpha_beta = max_size(alpha, beta);
  size_t max_size_seq_view = max_size(n, alpha, beta);

  scalar_seq_view<decltype(value_of(alpha))> alpha_dbl(value_of(alpha));
  scalar_seq_view<decltype(value_of(beta))> beta_dbl(value_of(beta));

  VectorBuilder<!is_constant_all<T_shape>::value, T_partials_return, T_shape>
      digamma_alpha(size_alpha);
  if (!is_constant_all<T_shape>::value) {
    for (size_t i = 0; i < size_alpha; ++i) {
      digamma_alpha[i] = digamma(alpha_dbl[i]);
    }
  }

  VectorBuilder<true, T_partials_return, T_inv_scale> log1p_inv_beta(size_beta);
  VectorBuilder<true, T_partials_return, T_inv_scale> log1p_beta(size_beta);
  for (size_t i = 0; i < size_beta; ++i) {
    log1p_inv_beta[i] = log1p(inv(beta_dbl[i]));
    log1p_beta[i] = log1p(beta_dbl[i]);
  }

  VectorBuilder<!is_constant_all<T_inv_scale>::value, T_partials_return,
                T_shape, T_inv_scale>
      lambda_m_alpha_over_1p_beta(size_alpha_beta);
  if (!is_constant_all<T_inv_scale>::value) {
    for (size_t i = 0; i < size_alpha_beta; ++i) {
      lambda_m_alpha_over_1p_beta[i]
          = alpha_dbl[i] / beta_dbl[i] - alpha_dbl[i] / (1 + beta_dbl[i]);
    }
  }

  for (size_t i = 0; i < max_size_seq_view; i++) {
    if (include_summand<propto, T_shape>::value) {
      if (n_vec[i] != 0) {
        logp += binomial_coefficient_log(n_vec[i] + alpha_dbl[i] - 1.0,
                                         alpha_dbl[i] - 1.0);
      }
    }
    logp -= alpha_dbl[i] * log1p_inv_beta[i] + n_vec[i] * log1p_beta[i];

    if (!is_constant_all<T_shape>::value) {
      ops_partials.edge1_.partials_[i] += digamma(alpha_dbl[i] + n_vec[i])
                                          - digamma_alpha[i]
                                          - log1p_inv_beta[i];
    }
    if (!is_constant_all<T_inv_scale>::value) {
      ops_partials.edge2_.partials_[i]
          += lambda_m_alpha_over_1p_beta[i] - n_vec[i] / (beta_dbl[i] + 1.0);
    }
  }

  return ops_partials.build(logp);
}

template <typename T_n, typename T_shape, typename T_inv_scale>
inline return_type_t<T_shape, T_inv_scale> neg_binomial_lpmf(
    const T_n& n, const T_shape& alpha, const T_inv_scale& beta) {
  return neg_binomial_lpmf<false>(n, alpha, beta);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * This program 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 General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact SUSE LLC.
 *
 * To contact SUSE LLC about this file by physical or electronic mail, you may
 * find current contact information at www.suse.com.
 */

#include <boost/algorithm/string/join.hpp>

#include "storage/CompoundAction/Formatter/Btrfs.h"
#include "storage/Filesystems/MountPoint.h"

namespace storage
{

    CompoundAction::Formatter::Btrfs::Btrfs(const CompoundAction::Impl* compound_action) :
	CompoundAction::Formatter(compound_action),
	btrfs(to_btrfs(compound_action->get_target_device()))
    {}

    string
    CompoundAction::Formatter::Btrfs::blk_devices_string_representation() const
    {
	vector<string> names;
	for (auto device : btrfs->get_blk_devices())
	    names.push_back(device->get_displayname());

	return boost::algorithm::join(names, ", ");
    }

    Text
    CompoundAction::Formatter::Btrfs::text() const
    {
	if (has_delete<storage::Btrfs>())
	    return delete_text();

	else if (has_create<storage::Btrfs>())
	{
	    if (has_create<storage::MountPoint>())
		return create_and_mount_text();

	    else
		return create_text();
	}

	else if (has_create<storage::MountPoint>())
	    return mount_text();

	else if (has_delete<storage::MountPoint>())
	    return unmount_text();

	else
	    return default_text();
    }

    Text
    CompoundAction::Formatter::Btrfs::delete_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2)
        Text text = _("Delete file system btrfs on %1$s");

        return sformat(text, blk_devices_string_representation().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::create_and_mount_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2),
	// %2$s is replaced with the mount point (e.g. /home)
        Text text = _("Create file system btrfs on %1$s and mount at %2$s");

        return sformat(text,
		       blk_devices_string_representation().c_str(),
		       btrfs->get_mount_point()->get_path().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::create_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2)
        Text text = _("Create file system btrfs on %1$s");

        return sformat(text, blk_devices_string_representation().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::mount_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2),
	// %2$s is replaced with the mount point (e.g. /home)
        Text text = _("Mount file system btrfs on %1$s at %2$s");

        return sformat(text,
		       blk_devices_string_representation().c_str(),
		       btrfs->get_mount_point()->get_path().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::unmount_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2),
	// %2$s is replaced with the mount point (e.g. /home)
        Text text = _("Unmount file system btrfs on %1$s at %2$s");

        return sformat(text,
		       blk_devices_string_representation().c_str(),
		       btrfs->get_mount_point()->get_path().c_str());
    }

}
<commit_msg>Use inherited methods<commit_after>/*
 * Copyright (c) 2017 SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * This program 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 General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact SUSE LLC.
 *
 * To contact SUSE LLC about this file by physical or electronic mail, you may
 * find current contact information at www.suse.com.
 */

#include <boost/algorithm/string/join.hpp>

#include "storage/CompoundAction/Formatter/Btrfs.h"
#include "storage/Filesystems/MountPoint.h"

namespace storage
{

    CompoundAction::Formatter::Btrfs::Btrfs(const CompoundAction::Impl* compound_action) :
	CompoundAction::Formatter(compound_action, "Btrfs"),
	btrfs(to_btrfs(compound_action->get_target_device()))
    {}

    string
    CompoundAction::Formatter::Btrfs::blk_devices_string_representation() const
    {
	vector<string> names;
	for (auto device : btrfs->get_blk_devices())
	    names.push_back(device->get_displayname());

	return boost::algorithm::join(names, ", ");
    }

    Text
    CompoundAction::Formatter::Btrfs::text() const
    {
	if ( deleting() )
	    return delete_text();

	else if ( creating() )
	{
	    if ( mounting() )
		return create_and_mount_text();

	    else
		return create_text();
	}

	else if ( mounting() )
	    return mount_text();

	else if ( has_delete<storage::MountPoint>() )
	    return unmount_text();

	else
	    return default_text();
    }

    Text
    CompoundAction::Formatter::Btrfs::delete_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2)
        Text text = _("Delete file system btrfs on %1$s");

        return sformat(text, blk_devices_string_representation().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::create_and_mount_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2),
	// %2$s is replaced with the mount point (e.g. /home)
        Text text = _("Create file system btrfs on %1$s and mount at %2$s");

        return sformat(text,
		       blk_devices_string_representation().c_str(),
		       btrfs->get_mount_point()->get_path().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::create_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2)
        Text text = _("Create file system btrfs on %1$s");

        return sformat(text, blk_devices_string_representation().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::mount_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2),
	// %2$s is replaced with the mount point (e.g. /home)
        Text text = _("Mount file system btrfs on %1$s at %2$s");

        return sformat(text,
		       blk_devices_string_representation().c_str(),
		       btrfs->get_mount_point()->get_path().c_str());
    }

    Text
    CompoundAction::Formatter::Btrfs::unmount_text() const
    {
	// TRANSLATORS:
	// %1$s is replaced with the names of the devices separated by comma (e.g. /dev/sda1, /dev/sda2),
	// %2$s is replaced with the mount point (e.g. /home)
        Text text = _("Unmount file system btrfs on %1$s at %2$s");

        return sformat(text,
		       blk_devices_string_representation().c_str(),
		       btrfs->get_mount_point()->get_path().c_str());
    }

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: decode.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 21:06:22 $
 *
 *  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
 *
 ************************************************************************/

#include "decode.hxx"

// ------------------------------------------------------------------------

struct GIFLZWTableEntry
{
    GIFLZWTableEntry*   pPrev;
    GIFLZWTableEntry*   pFirst;
    BYTE                nData;
};

// ------------------------------------------------------------------------

GIFLZWDecompressor::GIFLZWDecompressor( BYTE cDataSize ) :
            nInputBitsBuf       ( 0 ),
            nOutBufDataLen      ( 0 ),
            nInputBitsBufSize   ( 0 ),
            bEOIFound           ( FALSE ),
            nDataSize           ( cDataSize )
{
    pTable = new GIFLZWTableEntry[ 4096 ];
    pOutBuf = new BYTE[ 4096 ];

    nClearCode = 1 << nDataSize;
    nEOICode = nClearCode + 1;
    nTableSize = nEOICode + 1;
    nCodeSize = nDataSize + 1;
    nOldCode = 0xffff;
    pOutBufData = pOutBuf + 4096;

    for( USHORT i = 0; i < nTableSize; i++ )
    {
        pTable[i].pPrev = NULL;
        pTable[i].pFirst = pTable + i;
        pTable[i].nData = (BYTE) i;
    }
}

// ------------------------------------------------------------------------

GIFLZWDecompressor::~GIFLZWDecompressor()
{
    delete[] pOutBuf;
    delete[] pTable;
}

// ------------------------------------------------------------------------

HPBYTE GIFLZWDecompressor::DecompressBlock( HPBYTE pSrc, BYTE cBufSize,
                                            ULONG& rCount, BOOL& rEOI )
{
    ULONG   nTargetSize = 4096;
    ULONG   nCount = 0;
    HPBYTE  pTarget = (HPBYTE) rtl_allocateMemory( nTargetSize );
    HPBYTE  pTmpTarget = pTarget;

    nBlockBufSize = cBufSize;
    nBlockBufPos = 0;
    pBlockBuf = pSrc;

    while( ProcessOneCode() )
    {
        nCount += nOutBufDataLen;

        if( nCount > nTargetSize )
        {
            ULONG   nNewSize = nTargetSize << 1;
            ULONG   nOffset = pTmpTarget - pTarget;
            HPBYTE  pTmp = (HPBYTE) rtl_allocateMemory( nNewSize );

            memcpy( pTmp, pTarget, nTargetSize );
            rtl_freeMemory( pTarget );

            nTargetSize = nNewSize;
            pTmpTarget = ( pTarget = pTmp ) + nOffset;
        }

        memcpy( pTmpTarget, pOutBufData, nOutBufDataLen );
        pTmpTarget += nOutBufDataLen;
        pOutBufData += nOutBufDataLen;
        nOutBufDataLen = 0;

        if ( bEOIFound )
            break;
    }

    rCount = nCount;
    rEOI = bEOIFound;

    return pTarget;
}

// ------------------------------------------------------------------------

void GIFLZWDecompressor::AddToTable( USHORT nPrevCode, USHORT nCodeFirstData )
{
    GIFLZWTableEntry* pE;

    if( nTableSize < 4096 )
    {
        pE = pTable + nTableSize;
        pE->pPrev = pTable + nPrevCode;
        pE->pFirst = pE->pPrev->pFirst;
        pE->nData = pTable[ nCodeFirstData ].pFirst->nData;
        nTableSize++;

        if ( ( nTableSize == (USHORT) (1 << nCodeSize) ) && ( nTableSize < 4096 ) )
            nCodeSize++;
    }
}

// ------------------------------------------------------------------------

BOOL GIFLZWDecompressor::ProcessOneCode()
{
    GIFLZWTableEntry*   pE;
    USHORT              nCode;
    BOOL                bRet = FALSE;
    BOOL                bEndOfBlock = FALSE;

    while( nInputBitsBufSize < nCodeSize )
    {
        if( nBlockBufPos >= nBlockBufSize )
        {
            bEndOfBlock = TRUE;
            break;
        }

        nInputBitsBuf |= ( (ULONG) pBlockBuf[ nBlockBufPos++ ] ) << nInputBitsBufSize;
        nInputBitsBufSize += 8;
    }

    if ( !bEndOfBlock )
    {
        // Einen Code aus dem Eingabe-Buffer holen:
        nCode = ( (USHORT) nInputBitsBuf ) & ( ~( 0xffff << nCodeSize ) );
        nInputBitsBuf >>= nCodeSize;
        nInputBitsBufSize -= nCodeSize;

        if ( nCode < nClearCode )
        {
            if ( nOldCode != 0xffff )
                AddToTable( nOldCode, nCode );
        }
        else if ( ( nCode > nEOICode ) && ( nCode <= nTableSize ) )
        {
            if ( nCode == nTableSize )
                AddToTable( nOldCode, nOldCode );
            else
                AddToTable( nOldCode, nCode );
        }
        else
        {
            if ( nCode == nClearCode )
            {
                nTableSize = nEOICode + 1;
                nCodeSize = nDataSize + 1;
                nOldCode = 0xffff;
                nOutBufDataLen = 0;
            }
            else
                bEOIFound = TRUE;

            return TRUE;
        }

        nOldCode = nCode;

        // Zeichen(/-folge) des Codes nCode in den Ausgabe-Buffer schreiben:
        pE = pTable + nCode;
        do
        {
            nOutBufDataLen++;
            *(--pOutBufData) = pE->nData;
            pE = pE->pPrev;
        }
        while( pE );

        bRet = TRUE;
    }

    return bRet;
}
<commit_msg>INTEGRATION: CWS pchfix02 (1.5.90); FILE MERGED 2006/09/01 17:43:07 kaib 1.5.90.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: decode.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 14:53:48 $
 *
 *  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_svtools.hxx"

#include "decode.hxx"

// ------------------------------------------------------------------------

struct GIFLZWTableEntry
{
    GIFLZWTableEntry*   pPrev;
    GIFLZWTableEntry*   pFirst;
    BYTE                nData;
};

// ------------------------------------------------------------------------

GIFLZWDecompressor::GIFLZWDecompressor( BYTE cDataSize ) :
            nInputBitsBuf       ( 0 ),
            nOutBufDataLen      ( 0 ),
            nInputBitsBufSize   ( 0 ),
            bEOIFound           ( FALSE ),
            nDataSize           ( cDataSize )
{
    pTable = new GIFLZWTableEntry[ 4096 ];
    pOutBuf = new BYTE[ 4096 ];

    nClearCode = 1 << nDataSize;
    nEOICode = nClearCode + 1;
    nTableSize = nEOICode + 1;
    nCodeSize = nDataSize + 1;
    nOldCode = 0xffff;
    pOutBufData = pOutBuf + 4096;

    for( USHORT i = 0; i < nTableSize; i++ )
    {
        pTable[i].pPrev = NULL;
        pTable[i].pFirst = pTable + i;
        pTable[i].nData = (BYTE) i;
    }
}

// ------------------------------------------------------------------------

GIFLZWDecompressor::~GIFLZWDecompressor()
{
    delete[] pOutBuf;
    delete[] pTable;
}

// ------------------------------------------------------------------------

HPBYTE GIFLZWDecompressor::DecompressBlock( HPBYTE pSrc, BYTE cBufSize,
                                            ULONG& rCount, BOOL& rEOI )
{
    ULONG   nTargetSize = 4096;
    ULONG   nCount = 0;
    HPBYTE  pTarget = (HPBYTE) rtl_allocateMemory( nTargetSize );
    HPBYTE  pTmpTarget = pTarget;

    nBlockBufSize = cBufSize;
    nBlockBufPos = 0;
    pBlockBuf = pSrc;

    while( ProcessOneCode() )
    {
        nCount += nOutBufDataLen;

        if( nCount > nTargetSize )
        {
            ULONG   nNewSize = nTargetSize << 1;
            ULONG   nOffset = pTmpTarget - pTarget;
            HPBYTE  pTmp = (HPBYTE) rtl_allocateMemory( nNewSize );

            memcpy( pTmp, pTarget, nTargetSize );
            rtl_freeMemory( pTarget );

            nTargetSize = nNewSize;
            pTmpTarget = ( pTarget = pTmp ) + nOffset;
        }

        memcpy( pTmpTarget, pOutBufData, nOutBufDataLen );
        pTmpTarget += nOutBufDataLen;
        pOutBufData += nOutBufDataLen;
        nOutBufDataLen = 0;

        if ( bEOIFound )
            break;
    }

    rCount = nCount;
    rEOI = bEOIFound;

    return pTarget;
}

// ------------------------------------------------------------------------

void GIFLZWDecompressor::AddToTable( USHORT nPrevCode, USHORT nCodeFirstData )
{
    GIFLZWTableEntry* pE;

    if( nTableSize < 4096 )
    {
        pE = pTable + nTableSize;
        pE->pPrev = pTable + nPrevCode;
        pE->pFirst = pE->pPrev->pFirst;
        pE->nData = pTable[ nCodeFirstData ].pFirst->nData;
        nTableSize++;

        if ( ( nTableSize == (USHORT) (1 << nCodeSize) ) && ( nTableSize < 4096 ) )
            nCodeSize++;
    }
}

// ------------------------------------------------------------------------

BOOL GIFLZWDecompressor::ProcessOneCode()
{
    GIFLZWTableEntry*   pE;
    USHORT              nCode;
    BOOL                bRet = FALSE;
    BOOL                bEndOfBlock = FALSE;

    while( nInputBitsBufSize < nCodeSize )
    {
        if( nBlockBufPos >= nBlockBufSize )
        {
            bEndOfBlock = TRUE;
            break;
        }

        nInputBitsBuf |= ( (ULONG) pBlockBuf[ nBlockBufPos++ ] ) << nInputBitsBufSize;
        nInputBitsBufSize += 8;
    }

    if ( !bEndOfBlock )
    {
        // Einen Code aus dem Eingabe-Buffer holen:
        nCode = ( (USHORT) nInputBitsBuf ) & ( ~( 0xffff << nCodeSize ) );
        nInputBitsBuf >>= nCodeSize;
        nInputBitsBufSize -= nCodeSize;

        if ( nCode < nClearCode )
        {
            if ( nOldCode != 0xffff )
                AddToTable( nOldCode, nCode );
        }
        else if ( ( nCode > nEOICode ) && ( nCode <= nTableSize ) )
        {
            if ( nCode == nTableSize )
                AddToTable( nOldCode, nOldCode );
            else
                AddToTable( nOldCode, nCode );
        }
        else
        {
            if ( nCode == nClearCode )
            {
                nTableSize = nEOICode + 1;
                nCodeSize = nDataSize + 1;
                nOldCode = 0xffff;
                nOutBufDataLen = 0;
            }
            else
                bEOIFound = TRUE;

            return TRUE;
        }

        nOldCode = nCode;

        // Zeichen(/-folge) des Codes nCode in den Ausgabe-Buffer schreiben:
        pE = pTable + nCode;
        do
        {
            nOutBufDataLen++;
            *(--pOutBufData) = pE->nData;
            pE = pE->pPrev;
        }
        while( pE );

        bRet = TRUE;
    }

    return bRet;
}
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. 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 "tensorflow/core/data/service/grpc_util.h"

#include <algorithm>
#include <functional>
#include <string>

#include "tensorflow/core/data/service/common.h"
#include "tensorflow/core/distributed_runtime/rpc/grpc_util.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/env_time.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/status.h"

namespace tensorflow {
namespace data {
namespace grpc_util {

Status WrapError(const std::string& message, const ::grpc::Status& status) {
  if (status.ok()) {
    return errors::Internal("Expected a non-ok grpc status. Wrapping message: ",
                            message);
  } else {
    Status s = FromGrpcStatus(status);
    return Status(s.code(),
                  absl::StrCat(message, ": ", status.error_message()));
  }
}

Status Retry(const std::function<Status()>& f, const std::string& description,
             int64_t deadline_micros) {
  return Retry(
      f, [] { return true; }, description, deadline_micros);
}

Status Retry(const std::function<Status()>& f,
             const std::function<bool()>& should_retry,
             const std::string& description, int64_t deadline_micros) {
  Status s = f();
  for (int num_retries = 0;; ++num_retries) {
    if (!IsPreemptedError(s)) {
      return s;
    }
    int64_t now_micros = EnvTime::NowMicros();
    if (now_micros > deadline_micros || !should_retry()) {
      return s;
    }
    int64_t deadline_with_backoff_micros =
        now_micros + ::tensorflow::ComputeBackoffMicroseconds(num_retries);
    // Wait for a short period of time before retrying. If our backoff would put
    // us past the deadline, we truncate it to ensure our attempt starts before
    // the deadline.
    int64_t backoff_until =
        std::min(deadline_with_backoff_micros, deadline_micros);
    int64_t wait_time_micros = backoff_until - now_micros;
    if (wait_time_micros > 100 * 1000) {
      LOG(INFO) << "Failed to " << description << ": " << s
                << ". Will retry in " << wait_time_micros / 1000 << "ms.";
    }
    Env::Default()->SleepForMicroseconds(wait_time_micros);
    s = f();
  }
  return s;
}

}  // namespace grpc_util
}  // namespace data
}  // namespace tensorflow
<commit_msg>#tf-data-service Convert all "Stream Removed" errors to Unavailable status.<commit_after>/* Copyright 2020 The TensorFlow Authors. 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 "tensorflow/core/data/service/grpc_util.h"

#include <algorithm>
#include <functional>
#include <string>

#include "tensorflow/core/data/service/common.h"
#include "tensorflow/core/distributed_runtime/rpc/grpc_util.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/env_time.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/status.h"

namespace tensorflow {
namespace data {
namespace grpc_util {

constexpr char kStreamRemovedMessage[] = "Stream removed";

Status WrapError(const std::string& message, const ::grpc::Status& status) {
  if (status.ok()) {
    return errors::Internal("Expected a non-ok grpc status. Wrapping message: ",
                            message);
  } else {
    // FromGrpcStatus checks for "Stream removed" as well, but only when the
    // status code is "Unknown". We have observed that sometimes stream removed
    // errors use other status codes (b/258285154).
    // TODO(aaudibert): Upstream this to FromGrpcStatus.
    if (status.error_message() == kStreamRemovedMessage) {
      return Status(tensorflow::error::UNAVAILABLE, kStreamRemovedMessage);
    }
    Status s = FromGrpcStatus(status);
    return Status(s.code(),
                  absl::StrCat(message, ": ", status.error_message()));
  }
}

Status Retry(const std::function<Status()>& f, const std::string& description,
             int64_t deadline_micros) {
  return Retry(
      f, [] { return true; }, description, deadline_micros);
}

Status Retry(const std::function<Status()>& f,
             const std::function<bool()>& should_retry,
             const std::string& description, int64_t deadline_micros) {
  Status s = f();
  for (int num_retries = 0;; ++num_retries) {
    if (!IsPreemptedError(s)) {
      return s;
    }
    int64_t now_micros = EnvTime::NowMicros();
    if (now_micros > deadline_micros || !should_retry()) {
      return s;
    }
    int64_t deadline_with_backoff_micros =
        now_micros + ::tensorflow::ComputeBackoffMicroseconds(num_retries);
    // Wait for a short period of time before retrying. If our backoff would put
    // us past the deadline, we truncate it to ensure our attempt starts before
    // the deadline.
    int64_t backoff_until =
        std::min(deadline_with_backoff_micros, deadline_micros);
    int64_t wait_time_micros = backoff_until - now_micros;
    if (wait_time_micros > 100 * 1000) {
      LOG(INFO) << "Failed to " << description << ": " << s
                << ". Will retry in " << wait_time_micros / 1000 << "ms.";
    }
    Env::Default()->SleepForMicroseconds(wait_time_micros);
    s = f();
  }
  return s;
}

}  // namespace grpc_util
}  // namespace data
}  // namespace tensorflow
<|endoftext|>


<commit_before>// Check handle_bus flag
// Defaults to true
// RUN: %clangxx_asan -std=c++11 %s -o %t
// RUN: not %run %t %T/file 2>&1 | FileCheck %s -check-prefix=CHECK-BUS
// RUN: %env_asan_opts=handle_sigbus=0 not --crash %run %t %T/file 2>&1 | FileCheck %s

// UNSUPPORTED: ios

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

char array[4096];
int main(int argc, char **argv) {
  assert(argc > 1);
  int fd = open(argv[1], O_RDWR | O_CREAT, 0700);
  if (fd < 0) {
    perror("open");
    exit(1);
  }
  assert(write(fd, array, sizeof(array)) == sizeof(array));

  // Write some zeroes to the file, then mmap it while it has a 4KiB size
  char *addr = (char *)mmap(nullptr, sizeof(array), PROT_READ,
                            MAP_FILE | MAP_SHARED, fd, 0);
  if (addr == MAP_FAILED) {
    perror("mmap");
    exit(1);
  }

  // Truncate the file so our memory isn't valid any more
  assert(ftruncate(fd, 0) == 0);

  // Try to access the memory
  return addr[42];
  // CHECK-NOT: DEADLYSIGNAL
  // CHECK-BUS: DEADLYSIGNAL
  // CHECK-BUS: ERROR: AddressSanitizer: BUS
}
<commit_msg>[asan] Fix try to fix test on Android<commit_after>// Check handle_bus flag
// Defaults to true
// RUN: %clangxx_asan -std=c++11 %s -o %t
// RUN: not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-BUS
// RUN: %env_asan_opts=handle_sigbus=0 not --crash %run %t 2>&1 | FileCheck %s

// UNSUPPORTED: ios

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string>

char array[4096];
int main(int argc, char **argv) {
  int fd = open((std::string(argv[0]) + ".m").c_str(), O_RDWR | O_CREAT, 0700);
  if (fd < 0) {
    perror("open");
    exit(1);
  }
  assert(write(fd, array, sizeof(array)) == sizeof(array));

  // Write some zeroes to the file, then mmap it while it has a 4KiB size
  char *addr = (char *)mmap(nullptr, sizeof(array), PROT_READ,
                            MAP_FILE | MAP_SHARED, fd, 0);
  if (addr == MAP_FAILED) {
    perror("mmap");
    exit(1);
  }

  // Truncate the file so our memory isn't valid any more
  assert(ftruncate(fd, 0) == 0);

  // Try to access the memory
  return addr[42];
  // CHECK-NOT: DEADLYSIGNAL
  // CHECK-BUS: DEADLYSIGNAL
  // CHECK-BUS: ERROR: AddressSanitizer: BUS
}
<|endoftext|>


<commit_before>/** -*- c++ -*-
 * completionordereditor.cpp
 *
 *  Copyright (c) 2004 David Faure <faure@kde.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#include "completionordereditor.h"
#include "completionordereditor_p.h"
#include "ldapclient.h"
#include "resourceabc.h"

#include <QtDBus/QDBusConnection>

#include <kabc/stdaddressbook.h>
#include <kabc/resource.h>

#include <kdebug.h>
#include <klocale.h>
#include <kiconloader.h>
#include <k3listview.h>
#include <kpushbutton.h>

#include <khbox.h>
#include <kvbox.h>
#include <q3header.h>
#include <QToolButton>
#include <kapplication.h>

/*

Several items are used in addresseelineedit's completion object:
  LDAP servers, KABC resources (imap and non-imap), Recent addresses (in kmail only).

The default completion weights are as follow:
  LDAP: 50, 49, 48 etc.          (see ldapclient.cpp)
  KABC non-imap resources: 60    (see addresseelineedit.cpp and SimpleCompletionItem here)
  Distribution lists: 60         (see addresseelineedit.cpp and SimpleCompletionItem here)
  KABC imap resources: 80        (see kresources/imap/kabc/resourceimap.cpp)
  Recent addresses (kmail) : 120 (see kmail/kmcomposewin.cpp)

This dialog allows to change those weights, by showing one item per:
 - LDAP server
 - KABC non-imap resource
 - KABC imap subresource
 plus one item for Distribution Lists.

 Maybe 'recent addresses' should be configurable too, but first it might
 be better to add support for them in korganizer too.

*/

using namespace KPIM;

CompletionOrderEditorAdaptor::CompletionOrderEditorAdaptor(QObject *parent)
  : QDBusAbstractAdaptor(parent)
{
  setAutoRelaySignals(true);
}

int CompletionItemList::compareItems( Q3PtrCollection::Item s1, Q3PtrCollection::Item s2 )
{
  int w1 = ( (CompletionItem*)s1 )->completionWeight();
  int w2 = ( (CompletionItem*)s2 )->completionWeight();
  // s1 < s2 if it has a higher completion value, i.e. w1 > w2.
  return w2 - w1;
}

class LDAPCompletionItem : public CompletionItem
{
public:
  LDAPCompletionItem( LdapClient* ldapClient ) : mLdapClient( ldapClient ) {}
  virtual QString label() const { return i18n( "LDAP server %1", mLdapClient->server().host() ); }
  virtual int completionWeight() const { return mLdapClient->completionWeight(); }
  virtual void save( CompletionOrderEditor* );
protected:
  virtual void setCompletionWeight( int weight ) { mWeight = weight; }
private:
  LdapClient* mLdapClient;
  int mWeight;
};

void LDAPCompletionItem::save( CompletionOrderEditor* )
{
  KConfig config( "kabldaprc" );
  config.setGroup( "LDAP" );
  config.writeEntry( QString( "SelectedCompletionWeight%1" ).arg( mLdapClient->clientNumber() ),
                     mWeight );
  config.sync();
}

// A simple item saved into kpimcompletionorder (no subresources, just name/identifier/weight)
class SimpleCompletionItem : public CompletionItem
{
public:
  SimpleCompletionItem( CompletionOrderEditor* editor, const QString& label, const QString& identifier )
    : mLabel( label ), mIdentifier( identifier ) {
      KConfigGroup group( editor->configFile(), "CompletionWeights" );
      mWeight = group.readEntry( mIdentifier, 60 );
    }
  virtual QString label() const { return mLabel; }
  virtual int completionWeight() const { return mWeight; }
  virtual void save( CompletionOrderEditor* );
protected:
  virtual void setCompletionWeight( int weight ) { mWeight = weight; }
private:
  QString mLabel, mIdentifier;
  int mWeight;
};

void SimpleCompletionItem::save( CompletionOrderEditor* editor )
{
  // Maybe KABC::Resource could have a completionWeight setting (for readConfig/writeConfig)
  // But for kdelibs-3.2 compat purposes I can't do that.
  KConfigGroup group( editor->configFile(), "CompletionWeights" );
  group.writeEntry( mIdentifier, mWeight );
}

// An imap subresource for kabc
class KABCImapSubResCompletionItem : public CompletionItem
{
public:
  KABCImapSubResCompletionItem( ResourceABC* resource, const QString& subResource )
    : mResource( resource ), mSubResource( subResource ), mWeight( completionWeight() ) {}
  virtual QString label() const {
    return QString( "%1 %2" ).arg( mResource->resourceName() ).arg( mResource->subresourceLabel( mSubResource ) );
  }
  virtual int completionWeight() const {
    return mResource->subresourceCompletionWeight( mSubResource );
  }
  virtual void setCompletionWeight( int weight ) {
    mWeight = weight;
  }
  virtual void save( CompletionOrderEditor* ) {
    mResource->setSubresourceCompletionWeight( mSubResource, mWeight );
  }
private:
  ResourceABC* mResource;
  QString mSubResource;
  int mWeight;
};

/////////

class CompletionViewItem : public Q3ListViewItem
{
public:
  CompletionViewItem( Q3ListView* lv, CompletionItem* item )
    : Q3ListViewItem( lv, lv->lastItem(), item->label() ), mItem( item ) {}
  CompletionItem* item() const { return mItem; }
  void setItem( CompletionItem* i ) { mItem = i; setText( 0, mItem->label() ); }

private:
  CompletionItem* mItem;
};

CompletionOrderEditor::CompletionOrderEditor( KPIM::LdapSearch* ldapSearch,
                                              QWidget* parent )
  : KDialog( parent ), mConfig( "kpimcompletionorder" ), mDirty( false )
{
  setCaption( i18n( "Edit Completion Order" ) );
  setButtons( Ok|Cancel );
  setDefaultButton( Ok );
  setModal( true );
  enableButtonSeparator( true );
  new CompletionOrderEditorAdaptor( this );
  QDBus::sessionBus().registerObject("/", this, QDBusConnection::ExportAdaptors);
  mItems.setAutoDelete( true );
  // The first step is to gather all the data, creating CompletionItem objects
  QList< LdapClient* > ldapClients = ldapSearch->clients();
  for( QList<LdapClient*>::const_iterator it = ldapClients.begin(); it != ldapClients.end(); ++it ) {
    //kDebug(5300) << "LDAP: host " << (*it)->host() << " weight " << (*it)->completionWeight() << endl;
    mItems.append( new LDAPCompletionItem( *it ) );
  }
  KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
  QList<KABC::Resource*> resources = addressBook->resources();
  QListIterator<KABC::Resource*> resit( resources );
  while ( resit.hasNext() ) {
    KABC::Resource *resource = resit.next();
    //kDebug(5300) << "KABC Resource: " << (*resit)->className() << endl;
    ResourceABC* res = dynamic_cast<ResourceABC *>( resource  );
    if ( res ) { // IMAP KABC resource
      const QStringList subresources = res->subresources();
      for( QStringList::const_iterator it = subresources.begin(); it != subresources.end(); ++it ) {
        mItems.append( new KABCImapSubResCompletionItem( res, *it ) );
      }
    } else { // non-IMAP KABC resource
      mItems.append( new SimpleCompletionItem( this, resource->resourceName(),
                                               resource->identifier() ) );
    }
  }

#ifndef KDEPIM_NEW_DISTRLISTS // new distr lists are normal contact, so no separate item if using them
  // Add an item for distribution lists
  mItems.append( new SimpleCompletionItem( this, i18n( "Distribution Lists" ), "DistributionLists" ) );
#endif

  // Now sort the items, then create the GUI
  mItems.sort();

  KHBox* page = new KHBox( this );
  setMainWidget( page );
  mListView = new K3ListView( page );
  mListView->setSorting( -1 );
  mListView->addColumn( QString() );
  mListView->header()->hide();

  for( Q3PtrListIterator<CompletionItem> compit( mItems ); *compit; ++compit ) {
    new CompletionViewItem( mListView, *compit );
    kDebug(5300) << "  " << (*compit)->label() << " " << (*compit)->completionWeight() << endl;
  }

  KVBox* upDownBox = new KVBox( page );
  mUpButton = new KPushButton( upDownBox );
  mUpButton->setObjectName( "mUpButton" );
  mUpButton->setIcon( BarIconSet( "up", K3Icon::SizeSmall ) );
  mUpButton->setEnabled( false ); // b/c no item is selected yet
  mUpButton->setFocusPolicy( Qt::StrongFocus );

  mDownButton = new KPushButton( upDownBox );
  mDownButton->setObjectName( "mDownButton" );
  mDownButton->setIcon( BarIconSet( "down", K3Icon::SizeSmall ) );
  mDownButton->setEnabled( false ); // b/c no item is selected yet
  mDownButton->setFocusPolicy( Qt::StrongFocus );

  QWidget* spacer = new QWidget( upDownBox );
  upDownBox->setStretchFactor( spacer, 100 );

  connect( mListView, SIGNAL( selectionChanged( Q3ListViewItem* ) ),
           SLOT( slotSelectionChanged( Q3ListViewItem* ) ) );
  connect( mUpButton, SIGNAL( clicked() ), this, SLOT( slotMoveUp() ) );
  connect( mDownButton, SIGNAL( clicked() ), this, SLOT( slotMoveDown() ) );
}

CompletionOrderEditor::~CompletionOrderEditor()
{
}

void CompletionOrderEditor::slotSelectionChanged( Q3ListViewItem *item )
{
  mDownButton->setEnabled( item && item->itemBelow() );
  mUpButton->setEnabled( item && item->itemAbove() );
}

static void swapItems( CompletionViewItem *one, CompletionViewItem *other )
{
  CompletionItem* i = one->item();
  one->setItem( other->item() );
  other->setItem( i );
}

void CompletionOrderEditor::slotMoveUp()
{
  CompletionViewItem *item = static_cast<CompletionViewItem *>( mListView->selectedItem() );
  if ( !item ) return;
  CompletionViewItem *above = static_cast<CompletionViewItem *>( item->itemAbove() );
  if ( !above ) return;
  swapItems( item, above );
  mListView->setCurrentItem( above );
  mListView->setSelected( above, true );
  mDirty = true;
}

void CompletionOrderEditor::slotMoveDown()
{
  CompletionViewItem *item = static_cast<CompletionViewItem *>( mListView->selectedItem() );
  if ( !item ) return;
  CompletionViewItem *below = static_cast<CompletionViewItem *>( item->itemBelow() );
  if ( !below ) return;
  swapItems( item, below );
  mListView->setCurrentItem( below );
  mListView->setSelected( below, true );
  mDirty = true;
}

void CompletionOrderEditor::slotOk()
{
  if ( mDirty ) {
    int w = 100;
    for ( Q3ListViewItem* it = mListView->firstChild(); it; it = it->nextSibling() ) {
      CompletionViewItem *item = static_cast<CompletionViewItem *>( it );
      item->item()->setCompletionWeight( w );
      item->item()->save( this );
      kDebug(5300) << "slotOk:   " << item->item()->label() << " " << w << endl;
      --w;
    }
    emit completionOrderChanged();
  }
  KDialog::accept();
}

#include "completionordereditor_p.moc"
#include "completionordereditor.moc"
<commit_msg>simple compile fix<commit_after>/** -*- c++ -*-
 * completionordereditor.cpp
 *
 *  Copyright (c) 2004 David Faure <faure@kde.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#include "completionordereditor.h"
#include "completionordereditor_p.h"
#include "ldapclient.h"
#include "resourceabc.h"

#include <QtDBus/QDBusConnection>

#include <kabc/stdaddressbook.h>
#include <kabc/resource.h>

#include <kdebug.h>
#include <klocale.h>
#include <kiconloader.h>
#include <k3listview.h>
#include <kpushbutton.h>

#include <khbox.h>
#include <kvbox.h>
#include <q3header.h>
#include <QToolButton>
#include <kapplication.h>

/*

Several items are used in addresseelineedit's completion object:
  LDAP servers, KABC resources (imap and non-imap), Recent addresses (in kmail only).

The default completion weights are as follow:
  LDAP: 50, 49, 48 etc.          (see ldapclient.cpp)
  KABC non-imap resources: 60    (see addresseelineedit.cpp and SimpleCompletionItem here)
  Distribution lists: 60         (see addresseelineedit.cpp and SimpleCompletionItem here)
  KABC imap resources: 80        (see kresources/imap/kabc/resourceimap.cpp)
  Recent addresses (kmail) : 120 (see kmail/kmcomposewin.cpp)

This dialog allows to change those weights, by showing one item per:
 - LDAP server
 - KABC non-imap resource
 - KABC imap subresource
 plus one item for Distribution Lists.

 Maybe 'recent addresses' should be configurable too, but first it might
 be better to add support for them in korganizer too.

*/

using namespace KPIM;

CompletionOrderEditorAdaptor::CompletionOrderEditorAdaptor(QObject *parent)
  : QDBusAbstractAdaptor(parent)
{
  setAutoRelaySignals(true);
}

int CompletionItemList::compareItems( Q3PtrCollection::Item s1, Q3PtrCollection::Item s2 )
{
  int w1 = ( (CompletionItem*)s1 )->completionWeight();
  int w2 = ( (CompletionItem*)s2 )->completionWeight();
  // s1 < s2 if it has a higher completion value, i.e. w1 > w2.
  return w2 - w1;
}

class LDAPCompletionItem : public CompletionItem
{
public:
  LDAPCompletionItem( LdapClient* ldapClient ) : mLdapClient( ldapClient ) {}
  virtual QString label() const { return i18n( "LDAP server %1", mLdapClient->server().host() ); }
  virtual int completionWeight() const { return mLdapClient->completionWeight(); }
  virtual void save( CompletionOrderEditor* );
protected:
  virtual void setCompletionWeight( int weight ) { mWeight = weight; }
private:
  LdapClient* mLdapClient;
  int mWeight;
};

void LDAPCompletionItem::save( CompletionOrderEditor* )
{
  KConfig config( "kabldaprc" );
  config.setGroup( "LDAP" );
  config.writeEntry( QString( "SelectedCompletionWeight%1" ).arg( mLdapClient->clientNumber() ),
                     mWeight );
  config.sync();
}

// A simple item saved into kpimcompletionorder (no subresources, just name/identifier/weight)
class SimpleCompletionItem : public CompletionItem
{
public:
  SimpleCompletionItem( CompletionOrderEditor* editor, const QString& label, const QString& identifier )
    : mLabel( label ), mIdentifier( identifier ) {
      KConfigGroup group( editor->configFile(), "CompletionWeights" );
      mWeight = group.readEntry( mIdentifier, 60 );
    }
  virtual QString label() const { return mLabel; }
  virtual int completionWeight() const { return mWeight; }
  virtual void save( CompletionOrderEditor* );
protected:
  virtual void setCompletionWeight( int weight ) { mWeight = weight; }
private:
  QString mLabel, mIdentifier;
  int mWeight;
};

void SimpleCompletionItem::save( CompletionOrderEditor* editor )
{
  // Maybe KABC::Resource could have a completionWeight setting (for readConfig/writeConfig)
  // But for kdelibs-3.2 compat purposes I can't do that.
  KConfigGroup group( editor->configFile(), "CompletionWeights" );
  group.writeEntry( mIdentifier, mWeight );
}

// An imap subresource for kabc
class KABCImapSubResCompletionItem : public CompletionItem
{
public:
  KABCImapSubResCompletionItem( ResourceABC* resource, const QString& subResource )
    : mResource( resource ), mSubResource( subResource ), mWeight( completionWeight() ) {}
  virtual QString label() const {
    return QString( "%1 %2" ).arg( mResource->resourceName() ).arg( mResource->subresourceLabel( mSubResource ) );
  }
  virtual int completionWeight() const {
    return mResource->subresourceCompletionWeight( mSubResource );
  }
  virtual void setCompletionWeight( int weight ) {
    mWeight = weight;
  }
  virtual void save( CompletionOrderEditor* ) {
    mResource->setSubresourceCompletionWeight( mSubResource, mWeight );
  }
private:
  ResourceABC* mResource;
  QString mSubResource;
  int mWeight;
};

/////////

class CompletionViewItem : public Q3ListViewItem
{
public:
  CompletionViewItem( Q3ListView* lv, CompletionItem* item )
    : Q3ListViewItem( lv, lv->lastItem(), item->label() ), mItem( item ) {}
  CompletionItem* item() const { return mItem; }
  void setItem( CompletionItem* i ) { mItem = i; setText( 0, mItem->label() ); }

private:
  CompletionItem* mItem;
};

CompletionOrderEditor::CompletionOrderEditor( KPIM::LdapSearch* ldapSearch,
                                              QWidget* parent )
  : KDialog( parent ), mConfig( "kpimcompletionorder" ), mDirty( false )
{
  setCaption( i18n( "Edit Completion Order" ) );
  setButtons( Ok|Cancel );
  setDefaultButton( Ok );
  setModal( true );
  showButtonSeparator( true );
  new CompletionOrderEditorAdaptor( this );
  QDBus::sessionBus().registerObject("/", this, QDBusConnection::ExportAdaptors);
  mItems.setAutoDelete( true );
  // The first step is to gather all the data, creating CompletionItem objects
  QList< LdapClient* > ldapClients = ldapSearch->clients();
  for( QList<LdapClient*>::const_iterator it = ldapClients.begin(); it != ldapClients.end(); ++it ) {
    //kDebug(5300) << "LDAP: host " << (*it)->host() << " weight " << (*it)->completionWeight() << endl;
    mItems.append( new LDAPCompletionItem( *it ) );
  }
  KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
  QList<KABC::Resource*> resources = addressBook->resources();
  QListIterator<KABC::Resource*> resit( resources );
  while ( resit.hasNext() ) {
    KABC::Resource *resource = resit.next();
    //kDebug(5300) << "KABC Resource: " << (*resit)->className() << endl;
    ResourceABC* res = dynamic_cast<ResourceABC *>( resource  );
    if ( res ) { // IMAP KABC resource
      const QStringList subresources = res->subresources();
      for( QStringList::const_iterator it = subresources.begin(); it != subresources.end(); ++it ) {
        mItems.append( new KABCImapSubResCompletionItem( res, *it ) );
      }
    } else { // non-IMAP KABC resource
      mItems.append( new SimpleCompletionItem( this, resource->resourceName(),
                                               resource->identifier() ) );
    }
  }

#ifndef KDEPIM_NEW_DISTRLISTS // new distr lists are normal contact, so no separate item if using them
  // Add an item for distribution lists
  mItems.append( new SimpleCompletionItem( this, i18n( "Distribution Lists" ), "DistributionLists" ) );
#endif

  // Now sort the items, then create the GUI
  mItems.sort();

  KHBox* page = new KHBox( this );
  setMainWidget( page );
  mListView = new K3ListView( page );
  mListView->setSorting( -1 );
  mListView->addColumn( QString() );
  mListView->header()->hide();

  for( Q3PtrListIterator<CompletionItem> compit( mItems ); *compit; ++compit ) {
    new CompletionViewItem( mListView, *compit );
    kDebug(5300) << "  " << (*compit)->label() << " " << (*compit)->completionWeight() << endl;
  }

  KVBox* upDownBox = new KVBox( page );
  mUpButton = new KPushButton( upDownBox );
  mUpButton->setObjectName( "mUpButton" );
  mUpButton->setIcon( BarIconSet( "up", K3Icon::SizeSmall ) );
  mUpButton->setEnabled( false ); // b/c no item is selected yet
  mUpButton->setFocusPolicy( Qt::StrongFocus );

  mDownButton = new KPushButton( upDownBox );
  mDownButton->setObjectName( "mDownButton" );
  mDownButton->setIcon( BarIconSet( "down", K3Icon::SizeSmall ) );
  mDownButton->setEnabled( false ); // b/c no item is selected yet
  mDownButton->setFocusPolicy( Qt::StrongFocus );

  QWidget* spacer = new QWidget( upDownBox );
  upDownBox->setStretchFactor( spacer, 100 );

  connect( mListView, SIGNAL( selectionChanged( Q3ListViewItem* ) ),
           SLOT( slotSelectionChanged( Q3ListViewItem* ) ) );
  connect( mUpButton, SIGNAL( clicked() ), this, SLOT( slotMoveUp() ) );
  connect( mDownButton, SIGNAL( clicked() ), this, SLOT( slotMoveDown() ) );
}

CompletionOrderEditor::~CompletionOrderEditor()
{
}

void CompletionOrderEditor::slotSelectionChanged( Q3ListViewItem *item )
{
  mDownButton->setEnabled( item && item->itemBelow() );
  mUpButton->setEnabled( item && item->itemAbove() );
}

static void swapItems( CompletionViewItem *one, CompletionViewItem *other )
{
  CompletionItem* i = one->item();
  one->setItem( other->item() );
  other->setItem( i );
}

void CompletionOrderEditor::slotMoveUp()
{
  CompletionViewItem *item = static_cast<CompletionViewItem *>( mListView->selectedItem() );
  if ( !item ) return;
  CompletionViewItem *above = static_cast<CompletionViewItem *>( item->itemAbove() );
  if ( !above ) return;
  swapItems( item, above );
  mListView->setCurrentItem( above );
  mListView->setSelected( above, true );
  mDirty = true;
}

void CompletionOrderEditor::slotMoveDown()
{
  CompletionViewItem *item = static_cast<CompletionViewItem *>( mListView->selectedItem() );
  if ( !item ) return;
  CompletionViewItem *below = static_cast<CompletionViewItem *>( item->itemBelow() );
  if ( !below ) return;
  swapItems( item, below );
  mListView->setCurrentItem( below );
  mListView->setSelected( below, true );
  mDirty = true;
}

void CompletionOrderEditor::slotOk()
{
  if ( mDirty ) {
    int w = 100;
    for ( Q3ListViewItem* it = mListView->firstChild(); it; it = it->nextSibling() ) {
      CompletionViewItem *item = static_cast<CompletionViewItem *>( it );
      item->item()->setCompletionWeight( w );
      item->item()->save( this );
      kDebug(5300) << "slotOk:   " << item->item()->label() << " " << w << endl;
      --w;
    }
    emit completionOrderChanged();
  }
  KDialog::accept();
}

#include "completionordereditor_p.moc"
#include "completionordereditor.moc"
<|endoftext|>