<commit_before>#include <IOKit/IOLib.h>
#include <sys/errno.h>

#include "ButtonStatus.hpp"
#include "CallBackWrapper.hpp"
#include "CommonData.hpp"
#include "Config.hpp"
#include "Core.hpp"
#include "EventInputQueue.hpp"
#include "EventOutputQueue.hpp"
#include "EventWatcher.hpp"
#include "GlobalLock.hpp"
#include "IOLogWrapper.hpp"
#include "KeyCodeModifierFlagPairs.hpp"
#include "KeyboardRepeat.hpp"
#include "ListHookedConsumer.hpp"
#include "ListHookedKeyboard.hpp"
#include "ListHookedPointing.hpp"
#include "ModifierName.hpp"
#include "NumHeldDownKeys.hpp"
#include "PressDownKeys.hpp"
#include "RemapClass.hpp"
#include "RemapFunc/PointingRelativeToScroll.hpp"
#include "RemapFunc/common/DependingPressingPeriodKeyToKey.hpp"
#include "TimerWrapper.hpp"
#include "VirtualKey.hpp"

namespace org_pqrs_Karabiner {
  namespace Core {
    namespace {
      IOWorkLoop* workLoop = NULL;
    }

    void
    start(void)
    {
      GlobalLock::initialize();
      CommonData::initialize();
      KeyCodeModifierFlagPairs::initialize();
      ModifierName::initialize();
      EventWatcher::initialize();
      PressDownKeys::initialize();
      ButtonStatus::initialize();

      workLoop = IOWorkLoop::workLoop();
      if (! workLoop) {
        IOLOG_ERROR("IOWorkLoop::workLoop failed\n");
      } else {
        ListHookedDevice::initializeAll(*workLoop);

        KeyboardRepeat::initialize(*workLoop);
        EventInputQueue::initialize(*workLoop);
        VirtualKey::initialize(*workLoop);
        EventOutputQueue::initialize(*workLoop);
        RemapFunc::DependingPressingPeriodKeyToKey::static_initialize(*workLoop);
        RemapFunc::PointingRelativeToScroll::static_initialize(*workLoop);
        ListHookedKeyboard::static_initialize(*workLoop);
        RemapClassManager::initialize(*workLoop);
      }

      Config::sysctl_register();
    }

    void
    stop(void)
    {
      // Destroy global lock.
      // Then, all callbacks and hooked functions become inactive.
      GlobalLock::terminate();

      // ------------------------------------------------------------
      ListHookedDevice::terminateAll();

      // ------------------------------------------------------------
      // call terminate
      Config::sysctl_unregister();

      RemapClassManager::terminate();
      KeyboardRepeat::terminate();
      EventInputQueue::terminate();
      VirtualKey::terminate();
      EventOutputQueue::terminate();
      RemapFunc::DependingPressingPeriodKeyToKey::static_terminate();
      RemapFunc::PointingRelativeToScroll::static_terminate();
      ListHookedKeyboard::static_terminate();

      if (workLoop) {
        workLoop->release();
        workLoop = NULL;
      }

      EventWatcher::terminate();
      PressDownKeys::terminate();

      CommonData::terminate();
    }

    // ======================================================================
    bool
    IOHIKeyboard_gIOMatchedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIKeyboard, newService);
      if (! device) return false;

      ListHookedKeyboard::instance().push_back(new ListHookedKeyboard::Item(device));
      ListHookedConsumer::instance().push_back(new ListHookedConsumer::Item(device));
      return true;
    }

    bool
    IOHIKeyboard_gIOTerminatedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIKeyboard, newService);
      if (! device) return false;

      ListHookedKeyboard::instance().erase(device);
      ListHookedConsumer::instance().erase(device);
      return true;
    }

    bool
    IOHIPointing_gIOMatchedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIPointing, newService);
      if (! device) return false;

      ListHookedPointing::instance().push_back(new ListHookedPointing::Item(device));
      return true;
    }

    bool
    IOHIPointing_gIOTerminatedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIPointing, newService);
      if (! device) return false;

      ListHookedPointing::instance().erase(device);
      return true;
    }

    // ======================================================================
    namespace {
      void
      resetWhenNumHeldDownKeysIsZero(void)
      {
        if (NumHeldDownKeys::iszero()) {
          NumHeldDownKeys::reset();
          KeyboardRepeat::cancel();
          EventWatcher::reset();
          FlagStatus::globalFlagStatus().reset();
          ButtonStatus::reset();
          VirtualKey::reset();
          EventOutputQueue::FireModifiers::fire(FlagStatus::globalFlagStatus().makeFlags());
          EventOutputQueue::FireRelativePointer::fire();
          PressDownKeys::clear();
        }
      }
    }

    // ======================================================================
    void
    remap_KeyboardEventCallback(ParamsUnion& paramsUnion)
    {
      Params_KeyboardEventCallBack* params = paramsUnion.get_Params_KeyboardEventCallBack();
      if (! params) return;

      FlagStatus::globalFlagStatus().set(params->key, params->flags);

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      // ------------------------------------------------------------
      if (! remapParams.isremapped) {
        Params_KeyboardEventCallBack::auto_ptr ptr(Params_KeyboardEventCallBack::alloc(params->eventType,
                                                                                FlagStatus::globalFlagStatus().makeFlags(),
                                                                                params->key,
                                                                                params->charCode,
                                                                                params->charSet,
                                                                                params->origCharCode,
                                                                                params->origCharSet,
                                                                                params->keyboardType,
                                                                                false));
        if (ptr) {
          KeyboardRepeat::set(*ptr);
          EventOutputQueue::FireKey::fire(*ptr);
        }
      }

      resetWhenNumHeldDownKeysIsZero();

      RemapFunc::PointingRelativeToScroll::cancelScroll();
    }

    void
    remap_KeyboardSpecialEventCallback(ParamsUnion& paramsUnion)
    {
      Params_KeyboardSpecialEventCallback* params = paramsUnion.get_Params_KeyboardSpecialEventCallback();
      if (! params) return;

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      // ----------------------------------------
      if (! remapParams.isremapped) {
        Params_KeyboardSpecialEventCallback::auto_ptr ptr(
          Params_KeyboardSpecialEventCallback::alloc(
            params->eventType,
            FlagStatus::globalFlagStatus().makeFlags(),
            params->key,
            params->flavor,
            params->guid,
            false));
        if (ptr) {
          KeyboardRepeat::set(*ptr);
          EventOutputQueue::FireConsumer::fire(*ptr);
        }
      }

      resetWhenNumHeldDownKeysIsZero();

      RemapFunc::PointingRelativeToScroll::cancelScroll();
    }

    void
    remap_RelativePointerEventCallback(ParamsUnion& paramsUnion)
    {
      Params_RelativePointerEventCallback* params = paramsUnion.get_Params_RelativePointerEventCallback();
      if (! params) return;

      ButtonStatus::set(params->ex_button, params->ex_isbuttondown);

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      // ------------------------------------------------------------
      if (! remapParams.isremapped) {
        EventOutputQueue::FireRelativePointer::fire(ButtonStatus::makeButtons(), params->dx, params->dy);
      }

      if (params->ex_button != PointingButton::NONE) {
        resetWhenNumHeldDownKeysIsZero();
      }
    }

    void
    remap_ScrollWheelEventCallback(ParamsUnion& paramsUnion)
    {
      Params_ScrollWheelEventCallback* params = paramsUnion.get_Params_ScrollWheelEventCallback();
      if (! params) return;

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      if (! remapParams.isremapped) {
        EventOutputQueue::FireScrollWheel::fire(*params);
        RemapFunc::PointingRelativeToScroll::cancelScroll();
      }
    }
  }
}
<commit_msg>alloc -> constructor<commit_after>#include <IOKit/IOLib.h>
#include <sys/errno.h>

#include "ButtonStatus.hpp"
#include "CallBackWrapper.hpp"
#include "CommonData.hpp"
#include "Config.hpp"
#include "Core.hpp"
#include "EventInputQueue.hpp"
#include "EventOutputQueue.hpp"
#include "EventWatcher.hpp"
#include "GlobalLock.hpp"
#include "IOLogWrapper.hpp"
#include "KeyCodeModifierFlagPairs.hpp"
#include "KeyboardRepeat.hpp"
#include "ListHookedConsumer.hpp"
#include "ListHookedKeyboard.hpp"
#include "ListHookedPointing.hpp"
#include "ModifierName.hpp"
#include "NumHeldDownKeys.hpp"
#include "PressDownKeys.hpp"
#include "RemapClass.hpp"
#include "RemapFunc/PointingRelativeToScroll.hpp"
#include "RemapFunc/common/DependingPressingPeriodKeyToKey.hpp"
#include "TimerWrapper.hpp"
#include "VirtualKey.hpp"

namespace org_pqrs_Karabiner {
  namespace Core {
    namespace {
      IOWorkLoop* workLoop = NULL;
    }

    void
    start(void)
    {
      GlobalLock::initialize();
      CommonData::initialize();
      KeyCodeModifierFlagPairs::initialize();
      ModifierName::initialize();
      EventWatcher::initialize();
      PressDownKeys::initialize();
      ButtonStatus::initialize();

      workLoop = IOWorkLoop::workLoop();
      if (! workLoop) {
        IOLOG_ERROR("IOWorkLoop::workLoop failed\n");
      } else {
        ListHookedDevice::initializeAll(*workLoop);

        KeyboardRepeat::initialize(*workLoop);
        EventInputQueue::initialize(*workLoop);
        VirtualKey::initialize(*workLoop);
        EventOutputQueue::initialize(*workLoop);
        RemapFunc::DependingPressingPeriodKeyToKey::static_initialize(*workLoop);
        RemapFunc::PointingRelativeToScroll::static_initialize(*workLoop);
        ListHookedKeyboard::static_initialize(*workLoop);
        RemapClassManager::initialize(*workLoop);
      }

      Config::sysctl_register();
    }

    void
    stop(void)
    {
      // Destroy global lock.
      // Then, all callbacks and hooked functions become inactive.
      GlobalLock::terminate();

      // ------------------------------------------------------------
      ListHookedDevice::terminateAll();

      // ------------------------------------------------------------
      // call terminate
      Config::sysctl_unregister();

      RemapClassManager::terminate();
      KeyboardRepeat::terminate();
      EventInputQueue::terminate();
      VirtualKey::terminate();
      EventOutputQueue::terminate();
      RemapFunc::DependingPressingPeriodKeyToKey::static_terminate();
      RemapFunc::PointingRelativeToScroll::static_terminate();
      ListHookedKeyboard::static_terminate();

      if (workLoop) {
        workLoop->release();
        workLoop = NULL;
      }

      EventWatcher::terminate();
      PressDownKeys::terminate();

      CommonData::terminate();
    }

    // ======================================================================
    bool
    IOHIKeyboard_gIOMatchedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIKeyboard, newService);
      if (! device) return false;

      ListHookedKeyboard::instance().push_back(new ListHookedKeyboard::Item(device));
      ListHookedConsumer::instance().push_back(new ListHookedConsumer::Item(device));
      return true;
    }

    bool
    IOHIKeyboard_gIOTerminatedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIKeyboard, newService);
      if (! device) return false;

      ListHookedKeyboard::instance().erase(device);
      ListHookedConsumer::instance().erase(device);
      return true;
    }

    bool
    IOHIPointing_gIOMatchedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIPointing, newService);
      if (! device) return false;

      ListHookedPointing::instance().push_back(new ListHookedPointing::Item(device));
      return true;
    }

    bool
    IOHIPointing_gIOTerminatedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier)
    {
      GlobalLock::ScopedLock lk;
      if (! lk) return false;

      IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService);

      IOHIDevice* device = OSDynamicCast(IOHIPointing, newService);
      if (! device) return false;

      ListHookedPointing::instance().erase(device);
      return true;
    }

    // ======================================================================
    namespace {
      void
      resetWhenNumHeldDownKeysIsZero(void)
      {
        if (NumHeldDownKeys::iszero()) {
          NumHeldDownKeys::reset();
          KeyboardRepeat::cancel();
          EventWatcher::reset();
          FlagStatus::globalFlagStatus().reset();
          ButtonStatus::reset();
          VirtualKey::reset();
          EventOutputQueue::FireModifiers::fire(FlagStatus::globalFlagStatus().makeFlags());
          EventOutputQueue::FireRelativePointer::fire();
          PressDownKeys::clear();
        }
      }
    }

    // ======================================================================
    void
    remap_KeyboardEventCallback(ParamsUnion& paramsUnion)
    {
      Params_KeyboardEventCallBack* params = paramsUnion.get_Params_KeyboardEventCallBack();
      if (! params) return;

      FlagStatus::globalFlagStatus().set(params->key, params->flags);

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      // ------------------------------------------------------------
      if (! remapParams.isremapped) {
        Params_KeyboardEventCallBack p(params->eventType,
                                       FlagStatus::globalFlagStatus().makeFlags(),
                                       params->key,
                                       params->charCode,
                                       params->charSet,
                                       params->origCharCode,
                                       params->origCharSet,
                                       params->keyboardType,
                                       false);
        KeyboardRepeat::set(p);
        EventOutputQueue::FireKey::fire(p);
      }

      resetWhenNumHeldDownKeysIsZero();

      RemapFunc::PointingRelativeToScroll::cancelScroll();
    }

    void
    remap_KeyboardSpecialEventCallback(ParamsUnion& paramsUnion)
    {
      Params_KeyboardSpecialEventCallback* params = paramsUnion.get_Params_KeyboardSpecialEventCallback();
      if (! params) return;

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      // ----------------------------------------
      if (! remapParams.isremapped) {
        Params_KeyboardSpecialEventCallback::auto_ptr ptr(
          Params_KeyboardSpecialEventCallback::alloc(
            params->eventType,
            FlagStatus::globalFlagStatus().makeFlags(),
            params->key,
            params->flavor,
            params->guid,
            false));
        if (ptr) {
          KeyboardRepeat::set(*ptr);
          EventOutputQueue::FireConsumer::fire(*ptr);
        }
      }

      resetWhenNumHeldDownKeysIsZero();

      RemapFunc::PointingRelativeToScroll::cancelScroll();
    }

    void
    remap_RelativePointerEventCallback(ParamsUnion& paramsUnion)
    {
      Params_RelativePointerEventCallback* params = paramsUnion.get_Params_RelativePointerEventCallback();
      if (! params) return;

      ButtonStatus::set(params->ex_button, params->ex_isbuttondown);

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      // ------------------------------------------------------------
      if (! remapParams.isremapped) {
        EventOutputQueue::FireRelativePointer::fire(ButtonStatus::makeButtons(), params->dx, params->dy);
      }

      if (params->ex_button != PointingButton::NONE) {
        resetWhenNumHeldDownKeysIsZero();
      }
    }

    void
    remap_ScrollWheelEventCallback(ParamsUnion& paramsUnion)
    {
      Params_ScrollWheelEventCallback* params = paramsUnion.get_Params_ScrollWheelEventCallback();
      if (! params) return;

      RemapParams remapParams(paramsUnion);
      RemapClassManager::remap(remapParams);

      if (! remapParams.isremapped) {
        EventOutputQueue::FireScrollWheel::fire(*params);
        RemapFunc::PointingRelativeToScroll::cancelScroll();
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Nathan Binkert
 */

#ifndef __BASE_REFCNT_HH__
#define __BASE_REFCNT_HH__

class RefCounted
{
  private:
    int count;

  private:
    // Don't allow a default copy constructor or copy operator on
    // these objects because the default operation will copy the
    // reference count as well and we certainly don't want that.
    RefCounted(const RefCounted &);
    RefCounted &operator=(const RefCounted &);

  public:
    RefCounted() : count(0) {}
    virtual ~RefCounted() {}

    void incref() { ++count; }
    void decref() { if (--count <= 0) delete this; }
};

template <class T>
class RefCountingPtr
{
  protected:
    T *data;

    void copy(T *d)
    {
        data = d;
        if (data)
            data->incref();
    }
    void del()
    {
        if (data)
            data->decref();
    }
    void set(T *d)
    {
        if (data == d)
            return;

        del();
        copy(d);
    }

  public:
    RefCountingPtr() : data(0) {}
    RefCountingPtr(T *data) { copy(data); }
    RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
    ~RefCountingPtr() { del(); }

    T *operator->() { return data; }
    T &operator*() { return *data; }
    T *get() { return data; }

    const T *operator->() const { return data; }
    const T &operator*() const { return *data; }
    const T *get() const { return data; }

    const RefCountingPtr &operator=(T *p) { set(p); return *this; }
    const RefCountingPtr &operator=(const RefCountingPtr &r)
    { return operator=(r.data); }

    bool operator!() const { return data == 0; }
    operator bool() const { return data != 0; }
};

template<class T>
bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() == r.get(); }

template<class T>
bool operator==(const RefCountingPtr<T> &l, const T *r)
{ return l.get() == r; }

template<class T>
bool operator==(const T &l, const RefCountingPtr<T> &r)
{ return l == r.get(); }

template<class T>
bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() != r.get(); }

template<class T>
bool operator!=(const RefCountingPtr<T> &l, const T *r)
{ return l.get() != r; }

template<class T>
bool operator!=(const T &l, const RefCountingPtr<T> &r)
{ return l != r.get(); }

#endif // __BASE_REFCNT_HH__
<commit_msg>RefCount: Fix reference counting pointer == and != with a T* on the left.<commit_after>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Nathan Binkert
 */

#ifndef __BASE_REFCNT_HH__
#define __BASE_REFCNT_HH__

class RefCounted
{
  private:
    int count;

  private:
    // Don't allow a default copy constructor or copy operator on
    // these objects because the default operation will copy the
    // reference count as well and we certainly don't want that.
    RefCounted(const RefCounted &);
    RefCounted &operator=(const RefCounted &);

  public:
    RefCounted() : count(0) {}
    virtual ~RefCounted() {}

    void incref() { ++count; }
    void decref() { if (--count <= 0) delete this; }
};

template <class T>
class RefCountingPtr
{
  protected:
    T *data;

    void copy(T *d)
    {
        data = d;
        if (data)
            data->incref();
    }
    void del()
    {
        if (data)
            data->decref();
    }
    void set(T *d)
    {
        if (data == d)
            return;

        del();
        copy(d);
    }

  public:
    RefCountingPtr() : data(0) {}
    RefCountingPtr(T *data) { copy(data); }
    RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
    ~RefCountingPtr() { del(); }

    T *operator->() { return data; }
    T &operator*() { return *data; }
    T *get() { return data; }

    const T *operator->() const { return data; }
    const T &operator*() const { return *data; }
    const T *get() const { return data; }

    const RefCountingPtr &operator=(T *p) { set(p); return *this; }
    const RefCountingPtr &operator=(const RefCountingPtr &r)
    { return operator=(r.data); }

    bool operator!() const { return data == 0; }
    operator bool() const { return data != 0; }
};

template<class T>
bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() == r.get(); }

template<class T>
bool operator==(const RefCountingPtr<T> &l, const T *r)
{ return l.get() == r; }

template<class T>
bool operator==(const T *l, const RefCountingPtr<T> &r)
{ return l == r.get(); }

template<class T>
bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() != r.get(); }

template<class T>
bool operator!=(const RefCountingPtr<T> &l, const T *r)
{ return l.get() != r; }

template<class T>
bool operator!=(const T *l, const RefCountingPtr<T> &r)
{ return l != r.get(); }

#endif // __BASE_REFCNT_HH__
<|endoftext|>


<commit_before>#include "core.hpp"
#include "portable.hpp"

namespace tap {

static int long_traverse(PyObject *object, visitproc visit, void *arg) noexcept
{
	return 0;
}

static Py_ssize_t long_marshaled_size(PyObject *object) noexcept
{
	return sizeof (int64_t);
}

static int long_marshal(PyObject *object, void *buf, Py_ssize_t size, PeerObject &peer) noexcept
{
	*reinterpret_cast<int64_t *> (buf) = port(PyLong_AsLongLong(object));
	return 0;
}

static PyObject *long_unmarshal_alloc(const void *data, Py_ssize_t size, PeerObject &peer) noexcept
{
	if (size != sizeof (int64_t))
		return nullptr;

	return PyLong_FromLongLong(port(*reinterpret_cast<const int64_t *> (data)));
}

static int long_unmarshal_init(PyObject *object, const void *data, Py_ssize_t size, PeerObject &peer) noexcept
{
	return 0;
}

const TypeHandler long_type_handler = {
	LONG_TYPE_ID,
	long_traverse,
	long_marshaled_size,
	long_marshal,
	long_unmarshal_alloc,
	long_unmarshal_init,
};

} // namespace tap
<commit_msg>fail when int is out of supported range<commit_after>#include "core.hpp"
#include "portable.hpp"

namespace tap {

static int long_traverse(PyObject *object, visitproc visit, void *arg) noexcept
{
	return 0;
}

static Py_ssize_t long_marshaled_size(PyObject *object) noexcept
{
	return sizeof (int64_t);
}

static int long_marshal(PyObject *object, void *buf, Py_ssize_t size, PeerObject &peer) noexcept
{
	int overflow;
	int64_t value = PyLong_AsLongLongAndOverflow(object, &overflow);
	if (overflow != 0)
		return -1;

	*reinterpret_cast<int64_t *> (buf) = port(value);
	return 0;
}

static PyObject *long_unmarshal_alloc(const void *data, Py_ssize_t size, PeerObject &peer) noexcept
{
	if (size != sizeof (int64_t))
		return nullptr;

	return PyLong_FromLongLong(port(*reinterpret_cast<const int64_t *> (data)));
}

static int long_unmarshal_init(PyObject *object, const void *data, Py_ssize_t size, PeerObject &peer) noexcept
{
	return 0;
}

const TypeHandler long_type_handler = {
	LONG_TYPE_ID,
	long_traverse,
	long_marshaled_size,
	long_marshal,
	long_unmarshal_alloc,
	long_unmarshal_init,
};

} // namespace tap
<|endoftext|>


<commit_before>/* Copyright (c) 2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <sys/types.h>
#include <sys/epoll.h>
#include <QUuid>
#include <QFileInfo>
#include <TWebApplication>
#include <TSystemGlobal>
#include <THttpHeader>
#include "tepollsocket.h"
#include "tepollhttpsocket.h"
#include "tepoll.h"
#include "tsendbuffer.h"
#include "tfcore_unix.h"

class SendData;

static int sendBufSize = 0;
static int recvBufSize = 0;

TEpollSocket *TEpollSocket::accept(int listeningSocket)
{
    struct sockaddr_storage addr;
    socklen_t addrlen = sizeof(addr);

    int actfd = tf_accept4(listeningSocket, (sockaddr *)&addr, &addrlen, SOCK_CLOEXEC | SOCK_NONBLOCK);
    int err = errno;
    if (Q_UNLIKELY(actfd < 0)) {
        if (err != EAGAIN) {
            tSystemWarn("Failed accept.  errno:%d", err);
        }
        return NULL;
    }

    return create(actfd, QHostAddress((sockaddr *)&addr));
}

TEpollSocket *TEpollSocket::create(int socketDescriptor, const QHostAddress &address)
{
    TEpollSocket *sock = 0;

    if (Q_LIKELY(socketDescriptor > 0)) {
        sock  = new TEpollHttpSocket(socketDescriptor, address);
        sock->moveToThread(Tf::app()->thread());

        initBuffer(socketDescriptor);
    }

    return sock;
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &header, const QFileInfo &file, bool autoRemove, const TAccessLogger &logger)
{
    return new TSendBuffer(header, file, autoRemove, logger);
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &data)
{
    return new TSendBuffer(data);
}

void TEpollSocket::initBuffer(int socketDescriptor)
{
    const int BUF_SIZE = 128 * 1024;

    if (Q_UNLIKELY(sendBufSize == 0)) {
        // Creates a common buffer
        int res;
        socklen_t optlen;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_SNDBUF, &sendBufSize, &optlen);
        if (res < 0)
            sendBufSize = BUF_SIZE;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &recvBufSize, &optlen);
        if (res < 0)
            recvBufSize = BUF_SIZE;

    }
}

TEpollSocket::TEpollSocket(int socketDescriptor, const QHostAddress &address)
    : sd(socketDescriptor), uuid(), clientAddr(address)
{
    uuid = QUuid::createUuid().toByteArray();  // not thread safe
    tSystemDebug("TEpollSocket  id:%s", uuid.data());
}

TEpollSocket::~TEpollSocket()
{
    close();

    for (QListIterator<TSendBuffer*> it(sendBuf); it.hasNext(); ) {
        delete it.next();
    }
    sendBuf.clear();
}

/*!
  Receives data
  @return  0:success  -1:error
 */
int TEpollSocket::recv()
{
    int err;

    for (;;) {
        void *buf = getRecvBuffer(recvBufSize);
        errno = 0;
        int len = ::recv(sd, buf, recvBufSize, 0);
        err = errno;

        if (len <= 0) {
            break;
        }

        // Read successfully
        seekRecvBuffer(len);
    }

    int ret = 0;
    switch (err) {
    case EAGAIN:
        break;

    case 0:  // FALL THROUGH
    case ECONNRESET:
        tSystemDebug("Socket disconnected : errno:%d", err);
        ret = -1;
        break;

    default:
        tSystemError("Failed recv : errno:%d", err);
        ret = -1;
        break;
    }
    return ret;
}

/*!
  Sends data
  @return  0:success  -1:error
 */
int TEpollSocket::send()
{
    if (sendBuf.isEmpty()) {
        return 0;
    }

    int err = 0;
    int len;
    TSendBuffer *buf = sendBuf.first();
    TAccessLogger &logger = buf->accessLogger();

    for (;;) {
        len = sendBufSize;
        void *data = buf->getData(len);
        if (len == 0) {
            break;
        }

        errno = 0;
        len = ::send(sd, data, len, 0);
        err = errno;

        if (len > 0) {
            // Sent successfully
            buf->seekData(len);
            logger.setResponseBytes(logger.responseBytes() + len);
        } else {
            break;
        }
    }

    int ret = 0;
    switch (err) {
    case 0:  // FALL THROUGH
    case EAGAIN:
        break;

    case ECONNRESET:
        tSystemDebug("Socket disconnected : errno:%d", err);
        logger.setResponseBytes(-1);
        ret = -1;
        break;

    default:
        tSystemError("Failed send : errno:%d  len:%d", err, len);
        logger.setResponseBytes(-1);
        ret = -1;
        break;
    }

    if (err != EAGAIN && !sendBuf.isEmpty()) {
        TEpoll::instance()->modifyPoll(this, (EPOLLIN | EPOLLOUT | EPOLLET));  // reset
    }

    if (buf->atEnd() || ret < 0) {
        logger.write();  // Writes access log
        delete sendBuf.dequeue(); // delete send-buffer obj
    }

    return ret;
}

void TEpollSocket::enqueueSendData(TSendBuffer *buffer)
{
    sendBuf << buffer;
}

void TEpollSocket::setSocketDescpriter(int socketDescriptor)
{
    sd = socketDescriptor;
}

void TEpollSocket::close()
{
    if (sd > 0) {
        TF_CLOSE(sd);
        sd = 0;
    }
}
<commit_msg>fix a bug for EPIPE of sending packets.<commit_after>/* Copyright (c) 2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <sys/types.h>
#include <sys/epoll.h>
#include <QUuid>
#include <QFileInfo>
#include <TWebApplication>
#include <TSystemGlobal>
#include <THttpHeader>
#include "tepollsocket.h"
#include "tepollhttpsocket.h"
#include "tepoll.h"
#include "tsendbuffer.h"
#include "tfcore_unix.h"

class SendData;

static int sendBufSize = 0;
static int recvBufSize = 0;

TEpollSocket *TEpollSocket::accept(int listeningSocket)
{
    struct sockaddr_storage addr;
    socklen_t addrlen = sizeof(addr);

    int actfd = tf_accept4(listeningSocket, (sockaddr *)&addr, &addrlen, SOCK_CLOEXEC | SOCK_NONBLOCK);
    int err = errno;
    if (Q_UNLIKELY(actfd < 0)) {
        if (err != EAGAIN) {
            tSystemWarn("Failed accept.  errno:%d", err);
        }
        return NULL;
    }

    return create(actfd, QHostAddress((sockaddr *)&addr));
}

TEpollSocket *TEpollSocket::create(int socketDescriptor, const QHostAddress &address)
{
    TEpollSocket *sock = 0;

    if (Q_LIKELY(socketDescriptor > 0)) {
        sock  = new TEpollHttpSocket(socketDescriptor, address);
        sock->moveToThread(Tf::app()->thread());

        initBuffer(socketDescriptor);
    }

    return sock;
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &header, const QFileInfo &file, bool autoRemove, const TAccessLogger &logger)
{
    return new TSendBuffer(header, file, autoRemove, logger);
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &data)
{
    return new TSendBuffer(data);
}

void TEpollSocket::initBuffer(int socketDescriptor)
{
    const int BUF_SIZE = 128 * 1024;

    if (Q_UNLIKELY(sendBufSize == 0)) {
        // Creates a common buffer
        int res;
        socklen_t optlen;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_SNDBUF, &sendBufSize, &optlen);
        if (res < 0)
            sendBufSize = BUF_SIZE;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &recvBufSize, &optlen);
        if (res < 0)
            recvBufSize = BUF_SIZE;

    }
}

TEpollSocket::TEpollSocket(int socketDescriptor, const QHostAddress &address)
    : sd(socketDescriptor), uuid(), clientAddr(address)
{
    uuid = QUuid::createUuid().toByteArray();  // not thread safe
    tSystemDebug("TEpollSocket  id:%s", uuid.data());
}

TEpollSocket::~TEpollSocket()
{
    close();

    for (QListIterator<TSendBuffer*> it(sendBuf); it.hasNext(); ) {
        delete it.next();
    }
    sendBuf.clear();
}

/*!
  Receives data
  @return  0:success  -1:error
 */
int TEpollSocket::recv()
{
    int err;

    for (;;) {
        void *buf = getRecvBuffer(recvBufSize);
        errno = 0;
        int len = ::recv(sd, buf, recvBufSize, 0);
        err = errno;

        if (len <= 0) {
            break;
        }

        // Read successfully
        seekRecvBuffer(len);
    }

    int ret = 0;
    switch (err) {
    case EAGAIN:
        break;

    case 0:       // FALL THROUGH
    case ECONNRESET:
        tSystemDebug("Socket disconnected : errno:%d", err);
        ret = -1;
        break;

    default:
        tSystemError("Failed recv : errno:%d", err);
        ret = -1;
        break;
    }
    return ret;
}

/*!
  Sends data
  @return  0:success  -1:error
 */
int TEpollSocket::send()
{
    if (sendBuf.isEmpty()) {
        return 0;
    }

    int err = 0;
    int len;
    TSendBuffer *buf = sendBuf.first();
    TAccessLogger &logger = buf->accessLogger();

    for (;;) {
        len = sendBufSize;
        void *data = buf->getData(len);
        if (len == 0) {
            break;
        }

        errno = 0;
        len = ::send(sd, data, len, MSG_NOSIGNAL);
        err = errno;

        if (len <= 0) {
            break;
        }

        // Sent successfully
        buf->seekData(len);
        logger.setResponseBytes(logger.responseBytes() + len);
    }

    int ret = 0;
    switch (err) {
    case 0:     // FALL THROUGH
    case EAGAIN:
        break;

    case EPIPE:
        tSystemDebug("Socket disconnected : errno:%d", err);
        logger.setResponseBytes(-1);
        ret = -1;
        break;

    default:
        tSystemError("Failed send : errno:%d  len:%d", err, len);
        logger.setResponseBytes(-1);
        ret = -1;
        break;
    }

    if (buf->atEnd() || ret < 0) {
        logger.write();  // Writes access log
        delete sendBuf.dequeue(); // delete send-buffer obj
    }

    if (err != EAGAIN && !sendBuf.isEmpty()) {
        TEpoll::instance()->modifyPoll(this, (EPOLLIN | EPOLLOUT | EPOLLET));  // reset
    }

    return ret;
}

void TEpollSocket::enqueueSendData(TSendBuffer *buffer)
{
    sendBuf << buffer;
}

void TEpollSocket::setSocketDescpriter(int socketDescriptor)
{
    sd = socketDescriptor;
}

void TEpollSocket::close()
{
    if (sd > 0) {
        TF_CLOSE(sd);
        sd = 0;
    }
}
<|endoftext|>


<commit_before>#include "log.h"

#include <algorithm>
#include <array>
#include <chrono>
#include <exception>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>

using namespace allpix;

// NOTE: we have to check for exceptions before we do the actual logging (which may also throw exceptions)
DefaultLogger::DefaultLogger() : os(), exception_count_(get_uncaught_exceptions(true)), indent_count_(0) {}

DefaultLogger::~DefaultLogger() {
    // check if it is potentially safe to throw
    if(exception_count_ != get_uncaught_exceptions(false)) {
        return;
    }

    // get output string
    std::string out(os.str());

    // replace every newline by indented code if necessary
    auto start_pos = out.find('\n');
    if(start_pos != std::string::npos) {
        std::string spcs(indent_count_ + 1, ' ');
        spcs[0] = '\n';
        do {
            out.replace(start_pos, 1, spcs);
            start_pos += spcs.length();
        } while((start_pos = out.find('\n', start_pos)) != std::string::npos);
    }

    // add final newline
    out += '\n';

    // print output to streams
    for(auto stream : get_streams()) {
        (*stream) << out;
    }
}

std::ostringstream&
DefaultLogger::getStream(LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    // add date in all except short format
    if(get_format() != LogFormat::SHORT) {
        os << "|" << get_current_date() << "| ";
    }

    // add log level (shortly in the short format)
    if(get_format() != LogFormat::SHORT) {
        std::string level_str = "(";
        level_str += getStringFromLevel(level);
        level_str += ")";
        os << std::setw(9) << level_str << " ";
    } else
        os << "(" << getStringFromLevel(level).substr(0, 1) << ") ";

    // add section if available
    if(!get_section().empty()) {
        os << "[" << get_section() << "] ";
    }

    // print function name and line number information in debug format
    if(get_format() == LogFormat::DEBUG) {
        os << "<" << file << "/" << function << ":L" << line << "> ";
    }

    // save the indent count to fix with newlines
    indent_count_ = static_cast<unsigned int>(os.str().size());
    return os;
}

// reporting level
LogLevel& DefaultLogger::get_reporting_level() {
    static LogLevel reporting_level = LogLevel::INFO;
    return reporting_level;
}
void DefaultLogger::setReportingLevel(LogLevel level) {
    get_reporting_level() = level;
}
LogLevel DefaultLogger::getReportingLevel() {
    return get_reporting_level();
}
// convert string to log level and vice versa
std::string DefaultLogger::getStringFromLevel(LogLevel level) {
    static const std::array<std::string, 6> type = {{"QUIET", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG"}};
    return type.at(static_cast<decltype(type)::size_type>(level));
}

LogLevel DefaultLogger::getLevelFromString(std::string level) {
    std::transform(level.begin(), level.end(), level.begin(), ::toupper);

    if(level == "DEBUG") {
        return LogLevel::DEBUG;
    }
    if(level == "INFO") {
        return LogLevel::INFO;
    }
    if(level == "WARNING") {
        return LogLevel::WARNING;
    }
    if(level == "ERROR") {
        return LogLevel::ERROR;
    }
    if(level == "FATAL") {
        return LogLevel::FATAL;
    }
    if(level == "QUIET") {
        return LogLevel::QUIET;
    }

    throw std::invalid_argument("unknown log level");
}

// log format
LogFormat& DefaultLogger::get_format() {
    static LogFormat reporting_level = LogFormat::DEFAULT;
    return reporting_level;
}
void DefaultLogger::setFormat(LogFormat level) {
    get_format() = level;
}
LogFormat DefaultLogger::getFormat() {
    return get_format();
}
// convert string to log level and vice versa
std::string DefaultLogger::getStringFromFormat(LogFormat format) {
    static const std::array<std::string, 3> type = {{"SHORT", "DEFAULT", "DEBUG"}};
    return type.at(static_cast<decltype(type)::size_type>(format));
}

LogFormat DefaultLogger::getFormatFromString(std::string format) {
    std::transform(format.begin(), format.end(), format.begin(), ::toupper);
    if(format == "SHORT") {
        return LogFormat::SHORT;
    }
    if(format == "DEFAULT") {
        return LogFormat::DEFAULT;
    }
    if(format == "DEBUG") {
        return LogFormat::DEBUG;
    }

    throw std::invalid_argument("unknown log format");
}

// change streams
std::vector<std::ostream*>& DefaultLogger::get_streams() {
    static std::vector<std::ostream*> streams = {&std::cerr};
    return streams;
}
const std::vector<std::ostream*>& DefaultLogger::getStreams() {
    return get_streams();
}
void DefaultLogger::clearStreams() {
    get_streams().clear();
}
void DefaultLogger::addStream(std::ostream& stream) {
    get_streams().push_back(&stream);
}

// section names
std::string& DefaultLogger::get_section() {
    static std::string section;
    return section;
}
void DefaultLogger::setSection(std::string section) {
    get_section() = section;
}
std::string DefaultLogger::getSection() {
    return get_section();
}

std::string DefaultLogger::get_current_date() {
    // FIXME: revise this to get microseconds in a better way
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%X");

    auto seconds_from_epoch = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
    auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch() - seconds_from_epoch).count();
    ss << ".";
    ss << std::setfill('0') << std::setw(3);
    ss << millis;
    return ss.str();
}

int DefaultLogger::get_uncaught_exceptions(bool cons = false) {
#if __cplusplus > 201402L
    // we can only do this fully correctly in C++17
    return std::uncaught_exceptions();
#else
    if(cons) {
        return 0;
    }
    return static_cast<int>(std::uncaught_exception());
#endif
}
<commit_msg>fix lint<commit_after>#include "log.h"

#include <algorithm>
#include <array>
#include <chrono>
#include <exception>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>

using namespace allpix;

// NOTE: we have to check for exceptions before we do the actual logging (which may also throw exceptions)
DefaultLogger::DefaultLogger() : os(), exception_count_(get_uncaught_exceptions(true)), indent_count_(0) {}

DefaultLogger::~DefaultLogger() {
    // check if it is potentially safe to throw
    if(exception_count_ != get_uncaught_exceptions(false)) {
        return;
    }

    // get output string
    std::string out(os.str());

    // replace every newline by indented code if necessary
    auto start_pos = out.find('\n');
    if(start_pos != std::string::npos) {
        std::string spcs(indent_count_ + 1, ' ');
        spcs[0] = '\n';
        do {
            out.replace(start_pos, 1, spcs);
            start_pos += spcs.length();
        } while((start_pos = out.find('\n', start_pos)) != std::string::npos);
    }

    // add final newline
    out += '\n';

    // print output to streams
    for(auto stream : get_streams()) {
        (*stream) << out;
    }
}

std::ostringstream&
DefaultLogger::getStream(LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    // add date in all except short format
    if(get_format() != LogFormat::SHORT) {
        os << "|" << get_current_date() << "| ";
    }

    // add log level (shortly in the short format)
    if(get_format() != LogFormat::SHORT) {
        std::string level_str = "(";
        level_str += getStringFromLevel(level);
        level_str += ")";
        os << std::setw(9) << level_str << " ";
    } else {
        os << "(" << getStringFromLevel(level).substr(0, 1) << ") ";
    }

    // add section if available
    if(!get_section().empty()) {
        os << "[" << get_section() << "] ";
    }

    // print function name and line number information in debug format
    if(get_format() == LogFormat::DEBUG) {
        os << "<" << file << "/" << function << ":L" << line << "> ";
    }

    // save the indent count to fix with newlines
    indent_count_ = static_cast<unsigned int>(os.str().size());
    return os;
}

// reporting level
LogLevel& DefaultLogger::get_reporting_level() {
    static LogLevel reporting_level = LogLevel::INFO;
    return reporting_level;
}
void DefaultLogger::setReportingLevel(LogLevel level) {
    get_reporting_level() = level;
}
LogLevel DefaultLogger::getReportingLevel() {
    return get_reporting_level();
}
// convert string to log level and vice versa
std::string DefaultLogger::getStringFromLevel(LogLevel level) {
    static const std::array<std::string, 6> type = {{"QUIET", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG"}};
    return type.at(static_cast<decltype(type)::size_type>(level));
}

LogLevel DefaultLogger::getLevelFromString(std::string level) {
    std::transform(level.begin(), level.end(), level.begin(), ::toupper);

    if(level == "DEBUG") {
        return LogLevel::DEBUG;
    }
    if(level == "INFO") {
        return LogLevel::INFO;
    }
    if(level == "WARNING") {
        return LogLevel::WARNING;
    }
    if(level == "ERROR") {
        return LogLevel::ERROR;
    }
    if(level == "FATAL") {
        return LogLevel::FATAL;
    }
    if(level == "QUIET") {
        return LogLevel::QUIET;
    }

    throw std::invalid_argument("unknown log level");
}

// log format
LogFormat& DefaultLogger::get_format() {
    static LogFormat reporting_level = LogFormat::DEFAULT;
    return reporting_level;
}
void DefaultLogger::setFormat(LogFormat level) {
    get_format() = level;
}
LogFormat DefaultLogger::getFormat() {
    return get_format();
}
// convert string to log level and vice versa
std::string DefaultLogger::getStringFromFormat(LogFormat format) {
    static const std::array<std::string, 3> type = {{"SHORT", "DEFAULT", "DEBUG"}};
    return type.at(static_cast<decltype(type)::size_type>(format));
}

LogFormat DefaultLogger::getFormatFromString(std::string format) {
    std::transform(format.begin(), format.end(), format.begin(), ::toupper);
    if(format == "SHORT") {
        return LogFormat::SHORT;
    }
    if(format == "DEFAULT") {
        return LogFormat::DEFAULT;
    }
    if(format == "DEBUG") {
        return LogFormat::DEBUG;
    }

    throw std::invalid_argument("unknown log format");
}

// change streams
std::vector<std::ostream*>& DefaultLogger::get_streams() {
    static std::vector<std::ostream*> streams = {&std::cerr};
    return streams;
}
const std::vector<std::ostream*>& DefaultLogger::getStreams() {
    return get_streams();
}
void DefaultLogger::clearStreams() {
    get_streams().clear();
}
void DefaultLogger::addStream(std::ostream& stream) {
    get_streams().push_back(&stream);
}

// section names
std::string& DefaultLogger::get_section() {
    static std::string section;
    return section;
}
void DefaultLogger::setSection(std::string section) {
    get_section() = std::move(section);
}
std::string DefaultLogger::getSection() {
    return get_section();
}

std::string DefaultLogger::get_current_date() {
    // FIXME: revise this to get microseconds in a better way
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%X");

    auto seconds_from_epoch = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
    auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch() - seconds_from_epoch).count();
    ss << ".";
    ss << std::setfill('0') << std::setw(3);
    ss << millis;
    return ss.str();
}

int DefaultLogger::get_uncaught_exceptions(bool cons = false) {
#if __cplusplus > 201402L
    // we can only do this fully correctly in C++17
    return std::uncaught_exceptions();
#else
    if(cons) {
        return 0;
    }
    return static_cast<int>(std::uncaught_exception());
#endif
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_OPENCL_KERNEL_GENERATOR_LOAD_HPP
#define STAN_MATH_OPENCL_KERNEL_GENERATOR_LOAD_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/kernel_generator/type_str.hpp>
#include <stan/math/opencl/kernel_generator/name_generator.hpp>
#include <stan/math/opencl/kernel_generator/operation_cl.hpp>
#include <stan/math/opencl/kernel_generator/operation_cl_lhs.hpp>
#include <type_traits>
#include <string>
#include <utility>
#include <set>
#include <vector>

namespace stan {
namespace math {

/**
 * Represents an access to a \c matrix_cl in kernel generator expressions
 * @tparam T \c matrix_cl
 */
template <typename T>
class load_
    : public operation_cl_lhs<load_<T>,
                              typename std::remove_reference_t<T>::type> {
 protected:
  T a_;

 public:
  using Scalar = typename std::remove_reference_t<T>::type;
  using base = operation_cl<load_<T>, Scalar>;
  using base::var_name;
  static_assert(std::is_base_of<matrix_cl<Scalar>,
                                typename std::remove_reference_t<T>>::value,
                "load_: argument a must be a matrix_cl<T>!");
  static_assert(
      std::is_arithmetic<Scalar>::value,
      "load_: T in \"matrix_cl<T> a\" argument must be an arithmetic type!");

  /**
   * Constructor
   * @param a \c matrix_cl
   */
  explicit load_(T&& a) : a_(std::forward<T>(a)) {}

  /**
   * Creates a deep copy of this expression.
   * @return copy of \c *this
   */
  inline load_<T&> deep_copy() const& { return load_<T&>(a_); }
  inline load_<T> deep_copy() && { return load_<T>(std::forward<T>(a_)); }

  /**
   * generates kernel code for this expression.
   * @param i row index variable name
   * @param j column index variable name
   * @return part of kernel with code for this expression
   */
  inline kernel_parts generate(const std::string& i,
                               const std::string& j) const {
    kernel_parts res{};
    std::string type = type_str<Scalar>();
    res.body = type + " " + var_name + " = 0;"
               " if (!((!contains_nonzero(" + var_name + "_view, LOWER) && "
               + j + " < " + i + ") || (!contains_nonzero(" + var_name +
               "_view, UPPER) && " + j + " > " + i + "))) {"
               + var_name + " = " + var_name + "_global[" + i + " + " +
               var_name + "_rows * " + j + "];}\n";
    res.args = "__global " + type + "* " + var_name + "_global, int " + var_name
               + "_rows, int " + var_name + "_view, ";
    return res;
  }

  /**
   * generates kernel code for this expression if it appears on the left hand
   * side of an assignment.
   * @param i row index variable name
   * @param j column index variable name
   * @return part of kernel with code for this expressions
   */
  inline kernel_parts generate_lhs(const std::string& i,
                                   const std::string& j) const {
    kernel_parts res;
    std::string type = type_str<Scalar>();
    res.args = "__global " + type + "* " + var_name + "_global, int " + var_name
               + "_rows, int " + var_name + "_view, ";
    res.body
        = var_name + "_global[" + i + " + " + var_name + "_rows * " + j + "]";
    return res;
  }

  /**
   * Sets kernel arguments for this expression.
   * @param[in,out] generated set of expressions that already set their kernel
   * arguments
   * @param kernel kernel to set arguments on
   * @param[in,out] arg_num consecutive number of the first argument to set.
   * This is incremented for each argument set by this function.
   */
  inline void set_args(std::set<const operation_cl_base*>& generated,
                       cl::Kernel& kernel, int& arg_num) const {
    if (generated.count(this) == 0) {
      generated.insert(this);
      kernel.setArg(arg_num++, a_.buffer());
      kernel.setArg(arg_num++, a_.rows());
      kernel.setArg(arg_num++, a_.view());
    }
  }

  /**
   * Adds read event to the matrix used in this expression.
   * @param e the event to add
   */
  inline void add_read_event(cl::Event& e) const { a_.add_read_event(e); }

  /**
   * Adds write event to the matrix used in this expression.
   * @param e the event to add
   */
  inline void add_write_event(cl::Event& e) const { a_.add_write_event(e); }

  /**
   * Adds all read and write events on the matrix used by this expression to a
   * list and clears them from the matrix.
   * @param[out] events List of all events.
   */
  inline void get_clear_read_write_events(
      std::vector<cl::Event>& events) const {
    events.insert(events.end(), a_.read_events().begin(),
                  a_.read_events().end());
    events.insert(events.end(), a_.write_events().begin(),
                  a_.write_events().end());
    a_.clear_read_write_events();
  }

  /**
   * Adds all write events on the matrix used by this expression to a list and
   * clears them from the matrix.
   * @param[out] events List of all events.
   */
  inline void get_clear_write_events(std::vector<cl::Event>& events) const {
    events.insert(events.end(), a_.write_events().begin(),
                  a_.write_events().end());
    a_.clear_write_events();
  }

  /**
   * Number of rows of a matrix that would be the result of evaluating this
   * expression.
   * @return number of rows
   */
  inline int rows() const { return a_.rows(); }

  /**
   * Number of columns of a matrix that would be the result of evaluating this
   * expression.
   * @return number of columns
   */
  inline int cols() const { return a_.cols(); }

  /**
   * View of a matrix that would be the result of evaluating this expression.
   * @return view
   */
  inline matrix_cl_view view() const { return a_.view(); }

  /**
   * Sets view of the matrix depending on which part is written.
   * @param bottom_diagonal Index of the top sub- or super- diagonal written
   * with nonzero elements.
   * @param top_diagonal Index of the top sub- or super- diagonal written with
   * nonzero elements.
   * @param bottom_zero_diagonal Index of the top sub- or super- diagonal
   * written with zeros if it ie more extreme than \c bottom_diagonal. Otherwise
   * it should be set to equal value as \c bottom_diagonal.
   * @param top_zero_diagonal Index of the top sub- or super- diagonal written
   * with zeros if it ie more extreme than \c top_diagonal. Otherwise it should
   * be set to equal value as \c top_diagonal.
   */
  inline void set_view(int bottom_diagonal, int top_diagonal,
                       int bottom_zero_diagonal, int top_zero_diagonal) const {
    if (bottom_diagonal < 0) {
      a_.view(either(a_.view(), matrix_cl_view::Lower));
    } else if (bottom_zero_diagonal <= 1 - a_.rows()) {
      a_.view(both(a_.view(), matrix_cl_view::Upper));
    }
    if (top_diagonal > 0) {
      a_.view(either(a_.view(), matrix_cl_view::Upper));
    } else if (top_zero_diagonal >= a_.cols() - 1) {
      a_.view(both(a_.view(), matrix_cl_view::Lower));
    }
  }

  /**
   * Determine index of bottom diagonal written.
   * @return number of columns
   */
  inline int bottom_diagonal() const {
    return contains_nonzero(a_.view(), matrix_cl_view::Lower) ? -a_.rows() + 1
                                                              : 0;
  }

  /**
   * Determine index of top diagonal written.
   * @return number of columns
   */
  inline int top_diagonal() const {
    return contains_nonzero(a_.view(), matrix_cl_view::Upper) ? a_.cols() - 1
                                                              : 0;
  }

  /**
   * Evaluates the expression. \c load_ returns a const reference to stored
   * matrix_cl.
   * @return Result of the expression.
   */
  const T& eval() const { return a_; }

  /**
   * If needed resizes underlying matrix to desired number of rows and cols.
   * @param rows desired number of rows
   * @param cols desired number of columns
   */
  inline void check_assign_dimensions(int rows, int cols) const {
    if (a_.rows() != rows || a_.cols() != cols) {
      a_ = matrix_cl<Scalar>(rows, cols);
    }
  }
};

}  // namespace math
}  // namespace stan

#endif
#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 5.0.0-3~16.04.1 (tags/RELEASE_500/final)<commit_after>#ifndef STAN_MATH_OPENCL_KERNEL_GENERATOR_LOAD_HPP
#define STAN_MATH_OPENCL_KERNEL_GENERATOR_LOAD_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/kernel_generator/type_str.hpp>
#include <stan/math/opencl/kernel_generator/name_generator.hpp>
#include <stan/math/opencl/kernel_generator/operation_cl.hpp>
#include <stan/math/opencl/kernel_generator/operation_cl_lhs.hpp>
#include <type_traits>
#include <string>
#include <utility>
#include <set>
#include <vector>

namespace stan {
namespace math {

/**
 * Represents an access to a \c matrix_cl in kernel generator expressions
 * @tparam T \c matrix_cl
 */
template <typename T>
class load_
    : public operation_cl_lhs<load_<T>,
                              typename std::remove_reference_t<T>::type> {
 protected:
  T a_;

 public:
  using Scalar = typename std::remove_reference_t<T>::type;
  using base = operation_cl<load_<T>, Scalar>;
  using base::var_name;
  static_assert(std::is_base_of<matrix_cl<Scalar>,
                                typename std::remove_reference_t<T>>::value,
                "load_: argument a must be a matrix_cl<T>!");
  static_assert(
      std::is_arithmetic<Scalar>::value,
      "load_: T in \"matrix_cl<T> a\" argument must be an arithmetic type!");

  /**
   * Constructor
   * @param a \c matrix_cl
   */
  explicit load_(T&& a) : a_(std::forward<T>(a)) {}

  /**
   * Creates a deep copy of this expression.
   * @return copy of \c *this
   */
  inline load_<T&> deep_copy() const & { return load_<T&>(a_); }
  inline load_<T> deep_copy() && { return load_<T>(std::forward<T>(a_)); }

  /**
   * generates kernel code for this expression.
   * @param i row index variable name
   * @param j column index variable name
   * @return part of kernel with code for this expression
   */
  inline kernel_parts generate(const std::string& i,
                               const std::string& j) const {
    kernel_parts res{};
    std::string type = type_str<Scalar>();
    res.body = type + " " + var_name + " = 0;"
               " if (!((!contains_nonzero(" + var_name + "_view, LOWER) && "
               + j + " < " + i + ") || (!contains_nonzero(" + var_name +
               "_view, UPPER) && " + j + " > " + i + "))) {"
               + var_name + " = " + var_name + "_global[" + i + " + " +
               var_name + "_rows * " + j + "];}\n";
    res.args = "__global " + type + "* " + var_name + "_global, int " + var_name
               + "_rows, int " + var_name + "_view, ";
    return res;
  }

  /**
   * generates kernel code for this expression if it appears on the left hand
   * side of an assignment.
   * @param i row index variable name
   * @param j column index variable name
   * @return part of kernel with code for this expressions
   */
  inline kernel_parts generate_lhs(const std::string& i,
                                   const std::string& j) const {
    kernel_parts res;
    std::string type = type_str<Scalar>();
    res.args = "__global " + type + "* " + var_name + "_global, int " + var_name
               + "_rows, int " + var_name + "_view, ";
    res.body
        = var_name + "_global[" + i + " + " + var_name + "_rows * " + j + "]";
    return res;
  }

  /**
   * Sets kernel arguments for this expression.
   * @param[in,out] generated set of expressions that already set their kernel
   * arguments
   * @param kernel kernel to set arguments on
   * @param[in,out] arg_num consecutive number of the first argument to set.
   * This is incremented for each argument set by this function.
   */
  inline void set_args(std::set<const operation_cl_base*>& generated,
                       cl::Kernel& kernel, int& arg_num) const {
    if (generated.count(this) == 0) {
      generated.insert(this);
      kernel.setArg(arg_num++, a_.buffer());
      kernel.setArg(arg_num++, a_.rows());
      kernel.setArg(arg_num++, a_.view());
    }
  }

  /**
   * Adds read event to the matrix used in this expression.
   * @param e the event to add
   */
  inline void add_read_event(cl::Event& e) const { a_.add_read_event(e); }

  /**
   * Adds write event to the matrix used in this expression.
   * @param e the event to add
   */
  inline void add_write_event(cl::Event& e) const { a_.add_write_event(e); }

  /**
   * Adds all read and write events on the matrix used by this expression to a
   * list and clears them from the matrix.
   * @param[out] events List of all events.
   */
  inline void get_clear_read_write_events(
      std::vector<cl::Event>& events) const {
    events.insert(events.end(), a_.read_events().begin(),
                  a_.read_events().end());
    events.insert(events.end(), a_.write_events().begin(),
                  a_.write_events().end());
    a_.clear_read_write_events();
  }

  /**
   * Adds all write events on the matrix used by this expression to a list and
   * clears them from the matrix.
   * @param[out] events List of all events.
   */
  inline void get_clear_write_events(std::vector<cl::Event>& events) const {
    events.insert(events.end(), a_.write_events().begin(),
                  a_.write_events().end());
    a_.clear_write_events();
  }

  /**
   * Number of rows of a matrix that would be the result of evaluating this
   * expression.
   * @return number of rows
   */
  inline int rows() const { return a_.rows(); }

  /**
   * Number of columns of a matrix that would be the result of evaluating this
   * expression.
   * @return number of columns
   */
  inline int cols() const { return a_.cols(); }

  /**
   * View of a matrix that would be the result of evaluating this expression.
   * @return view
   */
  inline matrix_cl_view view() const { return a_.view(); }

  /**
   * Sets view of the matrix depending on which part is written.
   * @param bottom_diagonal Index of the top sub- or super- diagonal written
   * with nonzero elements.
   * @param top_diagonal Index of the top sub- or super- diagonal written with
   * nonzero elements.
   * @param bottom_zero_diagonal Index of the top sub- or super- diagonal
   * written with zeros if it ie more extreme than \c bottom_diagonal. Otherwise
   * it should be set to equal value as \c bottom_diagonal.
   * @param top_zero_diagonal Index of the top sub- or super- diagonal written
   * with zeros if it ie more extreme than \c top_diagonal. Otherwise it should
   * be set to equal value as \c top_diagonal.
   */
  inline void set_view(int bottom_diagonal, int top_diagonal,
                       int bottom_zero_diagonal, int top_zero_diagonal) const {
    if (bottom_diagonal < 0) {
      a_.view(either(a_.view(), matrix_cl_view::Lower));
    } else if (bottom_zero_diagonal <= 1 - a_.rows()) {
      a_.view(both(a_.view(), matrix_cl_view::Upper));
    }
    if (top_diagonal > 0) {
      a_.view(either(a_.view(), matrix_cl_view::Upper));
    } else if (top_zero_diagonal >= a_.cols() - 1) {
      a_.view(both(a_.view(), matrix_cl_view::Lower));
    }
  }

  /**
   * Determine index of bottom diagonal written.
   * @return number of columns
   */
  inline int bottom_diagonal() const {
    return contains_nonzero(a_.view(), matrix_cl_view::Lower) ? -a_.rows() + 1
                                                              : 0;
  }

  /**
   * Determine index of top diagonal written.
   * @return number of columns
   */
  inline int top_diagonal() const {
    return contains_nonzero(a_.view(), matrix_cl_view::Upper) ? a_.cols() - 1
                                                              : 0;
  }

  /**
   * Evaluates the expression. \c load_ returns a const reference to stored
   * matrix_cl.
   * @return Result of the expression.
   */
  const T& eval() const { return a_; }

  /**
   * If needed resizes underlying matrix to desired number of rows and cols.
   * @param rows desired number of rows
   * @param cols desired number of columns
   */
  inline void check_assign_dimensions(int rows, int cols) const {
    if (a_.rows() != rows || a_.cols() != cols) {
      a_ = matrix_cl<Scalar>(rows, cols);
    }
  }
};

}  // namespace math
}  // namespace stan

#endif
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_SCAL_META_AD_PROMOTABLE_HPP
#define STAN_MATH_PRIM_SCAL_META_AD_PROMOTABLE_HPP

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_arithmetic.hpp>

namespace stan {
namespace math {

/**
 * Template traits metaprogram to determine if a variable of one
 * template type can be promoted to a second target template
 * type. All variables are promotable to themselves, and all
 * primitive arithmetic types are promotable to double.
 *
 *
It will delcare an enum value equal to
 * false.
 *
 * @tparam V promoted type
 * @tparam T target type
 */
template <typename V, typename T>
struct ad_promotable {
  enum { value = false };
};

/**
 * Any type may be promoted to itself.
 *
 * @tparam T promoted and target type
 */
template <typename T>
struct ad_promotable<
    typename boost::enable_if<boost::is_arithmetic<T>, T>::type, T> {
  enum { value = true };
};
/**
 * A long double may be promoted to a double.
 */
template <>
struct ad_promotable<long double, double> {
  enum { value = true };
};

/**
 * A double may be promoted to a double.
 */
template <>
struct ad_promotable<double, double> {
  enum { value = true };
};

/**
 * A float may be promoted to a double.
 */
template <>
struct ad_promotable<float, double> {
  enum { value = true };
};

/**
 * A long may be promoted to a double.
 */
template <>
struct ad_promotable<long, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * An int may be promoted to a double.
 */
template <>
struct ad_promotable<int, double> {
  enum { value = true };
};

/**
 * A short may be promoted to a double.
 */
template <>
struct ad_promotable<short, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * A char may be promoted to a double.
 */
template <>
struct ad_promotable<char, double> {
  enum { value = true };
};

/**
 * A bool may be promoted to a double.
 */
template <>
struct ad_promotable<bool, double> {
  enum { value = true };
};

/**
 * An unsigned long may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned long, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * An unsigned int may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned int, double> {
  enum { value = true };
};

/**
 * An unsigned short may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned short, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * An unsigned char may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned char, double> {
  enum { value = true };
};

/**
 * A long long may be promoted to a double.
 */
template <>
struct ad_promotable<long long, double> {
  enum { value = true };
};

/**
 * A unsigned long long may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned long long, double> {
  enum { value = true };
};

}  // namespace math
}  // namespace stan
#endif
<commit_msg>reordering ad_promotable.hpp<commit_after>#ifndef STAN_MATH_PRIM_SCAL_META_AD_PROMOTABLE_HPP
#define STAN_MATH_PRIM_SCAL_META_AD_PROMOTABLE_HPP

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_arithmetic.hpp>

namespace stan {
namespace math {

/**
 * Template traits metaprogram to determine if a variable of one
 * template type can be promoted to a second target template
 * type. All variables are promotable to themselves, and all
 * primitive arithmetic types are promotable to double.
 *
 *
It will delcare an enum value equal to
 * false.
 *
 * @tparam V promoted type
 * @tparam T target type
 */
template <typename V, typename T>
struct ad_promotable {
  enum { value = false };
};

/**
 * Any type may be promoted to itself.
 *
 * @tparam T promoted and target type
 */
template <typename T>
struct ad_promotable<
    typename boost::enable_if<boost::is_arithmetic<T>, T>::type, T> {
  enum { value = true };
};

/**
 * A bool may be promoted to a double.
 */
template <>
struct ad_promotable<bool, double> {
  enum { value = true };
};

/**
 * A char may be promoted to a double.
 */
template <>
struct ad_promotable<char, double> {
  enum { value = true };
};

/**
 * An unsigned char may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned char, double> {
  enum { value = true };
};

/**
 * A short may be promoted to a double.
 */
template <>
struct ad_promotable<short, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * An unsigned short may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned short, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * An int may be promoted to a double.
 */
template <>
struct ad_promotable<int, double> {
  enum { value = true };
};

/**
 * An unsigned int may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned int, double> {
  enum { value = true };
};

/**
 * A long may be promoted to a double.
 */
template <>
struct ad_promotable<long, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * An unsigned long may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned long, double> {  // NOLINT(runtime/int)
  enum { value = true };
};

/**
 * A long long may be promoted to a double.
 */
template <>
struct ad_promotable<long long, double> {
  enum { value = true };
};

/**
 * An unsigned long long may be promoted to a double.
 */
template <>
struct ad_promotable<unsigned long long, double> {
  enum { value = true };
};

/**
 * A float may be promoted to a double.
 */
template <>
struct ad_promotable<float, double> {
  enum { value = true };
};

/**
 * A double may be promoted to a double.
 */
template <>
struct ad_promotable<double, double> {
  enum { value = true };
};

/**
 * A long double may be promoted to a double.
 */
template <>
struct ad_promotable<long double, double> {
  enum { value = true };
};

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