Program Listing for File lock_policy.h

Return to documentation for file (liberate/concurrency/lock_policy.h)

/*
 * This file is part of liberate.
 *
 * Author(s): Jens Finkhaeuser <jens@finkhaeuser.de>
 *
 * Copyright (c) 2021 Jens Finkhaeuser.
 * Copyright (c) 2022 Interpeer gUG (haftungsbeschränkt)
 *
 * SPDX-License-Identifier: GPL-3.0-only
 *
 * 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, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBERATE_CONCURRENCY_LOCK_POLICY_H
#define LIBERATE_CONCURRENCY_LOCK_POLICY_H

#ifndef __cplusplus
#error You are trying to include a C++ only header file
#endif

#include <liberate.h>

#include <memory>

namespace liberate::concurrency {

namespace detail {

struct null_mutex
{
};


template <typename mutexT>
struct null_lock
{
  template <typename discardT>
  inline null_lock(discardT &)
  {
  }
};


template<class T, class R = void>
struct enable_if_smart_ptr_type { typedef R type; };

template<class T, class Enable = void>
struct is_smart_ptr : std::false_type {};

template<class T>
struct is_smart_ptr<
  T,
  typename enable_if_smart_ptr_type<
    typename T::element_type
  >::type
> : std::true_type
{};


template <typename mutex_ptrT, typename lockT>
struct mutex_ptr_lock_proxy
{
  template <typename... argsT>
  inline mutex_ptr_lock_proxy( mutex_ptrT & mutex_ptr, argsT &&... args)
    : m_lock{*mutex_ptr, std::forward<argsT>(args)...}
  {
  }

  static inline lockT & lock_ref(mutex_ptr_lock_proxy & proxy)
  {
    return proxy.m_lock;
  }

  lockT m_lock;
};


template <
  typename mutexT,
  typename lockT,
  bool IS_POINTER,
  bool IS_SMART_POINTER
>
struct lock_selector
{
  // Also selected for IS_POINTER && IS_SMART_POINTER, which should never
  // happen, so it's good that it fails.
};

template <
  typename mutexT,
  typename lockT
>
struct lock_selector<mutexT, lockT, false, false>
{
  using mutex_type = mutexT;
  using lock_type = lockT;

  static inline lockT & lock_ref(lockT & lock)
  {
    return lock;
  }
};

template <
  typename mutexT,
  typename lockT
>
struct lock_selector<mutexT, lockT, true, false>
{
  using mutex_type = mutexT;
  using lock_type = mutex_ptr_lock_proxy<
    mutexT, lockT
  >;

  static inline lockT & lock_ref(lockT & lock)
  {
    return lock_type::lock_ref(lock);
  }
};

template <
  typename mutexT,
  typename lockT
>
struct lock_selector<mutexT, lockT, false, true>
{
  using mutex_type = mutexT;
  using lock_type = mutex_ptr_lock_proxy<
    mutexT, lockT
  >;

  static inline lockT & lock_ref(lockT & lock)
  {
    return lock_type::lock_ref(lock);
  }
};


} // namespace detail


struct null_lock_policy
{
  using mutex_type = detail::null_mutex;
  using lock_type = detail::null_lock<mutex_type>;

  using _passed_lock_type = lock_type;
};


template <typename mutexT, typename lockT>
struct lock_policy
{
  using _selector = detail::lock_selector<
    mutexT,
    lockT,
    std::is_pointer<mutexT>::value,
    detail::is_smart_ptr<mutexT>::value
  >;

  using mutex_type = typename _selector::mutex_type;

  using lock_type = typename _selector::lock_type;

  using _passed_lock_type = lockT;
};


template <typename lock_policyT>
inline typename lock_policyT::_passed_lock_type &
lock_ref(typename lock_policyT::lock_type & lock)
{
  return lock_policyT::_selector::lock_ref(lock);
}

template <>
inline typename null_lock_policy::_passed_lock_type &
lock_ref<null_lock_policy>(typename null_lock_policy::lock_type & lock)
{
  return lock;
}


} // namespace liberate::concurrency

#endif // guard