1// vi:set ft=cpp: -*- Mode: C++ -*-
2
3/* SPDX-License-Identifier: GPL-2.0-only or License-Ref-kk-custom */
4/*
5 * Copyright (C) 2013      Technische Universität Dresden.
6 * Copyright (C) 2014-2017 Kernkonzept GmbH.
7 */
8
9#pragma once
10
11#include "type_traits"
12
13namespace cxx
14{
15
16template< typename T >
17struct default_delete
18{
19  default_delete() {}
20
21  template< typename U >
22  default_delete(default_delete<U> const &) {}
23
24  void operator () (T *p) const
25  { delete p; }
26};
27
28template< typename T >
29struct default_delete<T[]>
30{
31  default_delete() {}
32
33  void operator () (T *p)
34  { delete [] p; }
35};
36
37template< typename T, typename C >
38struct unique_ptr_index_op {};
39
40template< typename T, typename C >
41struct unique_ptr_index_op<T[], C>
42{
43  typedef T &reference;
44  reference operator [] (int idx) const
45  { return static_cast<C const *>(this)->get()[idx]; }
46};
47
48template< typename T, typename T_Del = default_delete<T> >
49class unique_ptr : public unique_ptr_index_op<T, unique_ptr<T, T_Del> >
50{
51private:
52  struct _unspec;
53  typedef _unspec* _unspec_ptr_type;
54
55public:
56  typedef typename cxx::remove_extent<T>::type element_type;
57  typedef element_type *pointer;
58  typedef element_type &reference;
59  typedef T_Del deleter_type;
60
61  unique_ptr() : _ptr(pointer()) {}
62
63  explicit unique_ptr(pointer p) : _ptr(p) {}
64
65  unique_ptr(unique_ptr &&o) : _ptr(o.release()) {}
66
67  ~unique_ptr() { reset(); }
68
69  unique_ptr &operator = (unique_ptr &&o)
70  {
71    reset(o.release());
72    return *this;
73  }
74
75  unique_ptr &operator = (_unspec_ptr_type)
76  {
77    reset();
78    return *this;
79  }
80
81  element_type &operator * () const { return *get(); }
82  pointer operator -> () const { return get(); }
83
84  pointer get() const { return _ptr; }
85
86  operator _unspec_ptr_type () const
87  { return reinterpret_cast<_unspec_ptr_type>(get()); }
88
89  pointer release()
90  {
91    pointer r = _ptr;
92    _ptr = 0;
93    return r;
94  }
95
96  void reset(pointer p = pointer())
97  {
98    if (p != get())
99      {
100        deleter_type()(get());
101        _ptr = p;
102      }
103  }
104
105  unique_ptr(unique_ptr const &) = delete;
106  unique_ptr &operator = (unique_ptr const &) = delete;
107
108private:
109  pointer _ptr;
110};
111
112template< typename T >
113unique_ptr<T>
114make_unique_ptr(T *p)
115{ return unique_ptr<T>(p); }
116
117template< typename T >
118typename cxx::enable_if<cxx::is_array<T>::value, unique_ptr<T>>::type
119make_unique(unsigned long size)
120{ return cxx::unique_ptr<T>(new typename cxx::remove_extent<T>::type[size]()); }
121
122template< typename T, typename... Args >
123typename cxx::enable_if<!cxx::is_array<T>::value, unique_ptr<T>>::type
124make_unique(Args &&... args)
125{ return cxx::unique_ptr<T>(new T(cxx::forward<Args>(args)...)); }
126
127}
128