// vi:set ft=cpp: -*- Mode: C++ -*-
/*
 * Copyright (C) 2016, 2019-2020 Kernkonzept GmbH.
 * Author(s): Philipp Eppelt <philipp.eppelt@kernkonzept.com>
 *
 * This file is distributed under the terms of the GNU General Public
 * License, version 2. Please see the COPYING-GPL-2 file for details.
 *
 * As a special exception, you may use this file as part of a free software
 * library without restriction. Specifically, if other files instantiate
 * templates or use macros or inline functions from this file, or you compile
 * this file and link it with other files to produce an executable, this
 * file does not by itself cause the resulting executable to be covered by
 * the GNU General Public License. This exception does not however
 * invalidate any other reasons why the executable file might be covered by
 * the GNU General Public License.
 */
#pragma once

#include <memory>
#include <utility>

namespace std { namespace L4 {

template <typename T>
struct _Make_unique
{ using __single = ::std::unique_ptr<T>; };

template <typename T>
struct _Make_unique<T[]>
{ using __array = ::std::unique_ptr<T[]>; };

template <typename T, size_t SIZE>
struct _Make_unique<T[SIZE]>
{ struct __invalid { }; };

/// Create an object of type `T` and return it inside a std::unique_ptr.
template <typename T, typename... Args>
inline typename _Make_unique<T>::__single
make_unique(Args &&... args)
{
  return ::std::unique_ptr<T>(new T(::std::forward<Args>(args)...));
}

/// Allocate an array of type `T` and return it inside a std::unique_ptr.
template <typename T>
inline typename _Make_unique<T>::__array
make_unique(std::size_t size)
{
  return ::std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
}

/// Disable std::make_unqiue for arrays of known bound.
template <typename T, typename... Args>
inline typename _Make_unique<T>::__invalid
make_unique(Args &&...) = delete;
}} // namespace L4, namespace std
