-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathunique_ptr.h
735 lines (633 loc) · 26.1 KB
/
unique_ptr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_UNIQUE_PTR_H
#define EASTL_UNIQUE_PTR_H
#include <eastl/EABase/nullptr.h>
#include <eastl/internal/config.h>
#include <eastl/internal/smart_ptr.h> // Defines smart_ptr_deleter
#include <eastl/internal/move_help.h> // Defines EASTL_MOVE
#include <eastl/type_traits.h>
#include <eastl/utility.h>
#include <eastl/functional.h>
#include <eastl/bonus/compressed_pair.h>
#include <stddef.h>
#if defined(EASTL_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
namespace eastl
{
/// class unique_ptr
///
/// This class implements a unique_ptr template. This is a class which is
/// similar to the C++ auto_ptr template, except that it prohibits copying
/// of itself, for safety.
///
/// More specifically, the unique_ptr class template stores a pointer to a
/// dynamically allocated object. The object pointed to is automatically
/// deleted on destructor of unique_ptr or can be manually deleted via the
/// unique_ptr::reset function.
///
/// Memory allocation notes:
/// unique_ptr doesn't allocate memory; all allocated pointers are externally
/// derived. unique_ptr does deallocate memory, though always through the
/// user-provided deleter. You need to make sure you are consistent in providing
/// a deleter which frees memory in a way that matches how it was originally allocated.
/// Deleters have instance information and are moved between containers the same way
/// the allocated pointers are. Thus you can allocate memory via some heap and
/// provide a deleter which contains a pointer to that same heap, and regardless
/// of what you do with the unique_ptr, including moving it to another unique_ptr,
/// the deletion will use the originally provided heap.
///
/// Example usage:
/// unique_ptr<int> p(new int);
/// *p = 4;
///
/// unique_ptr<int[]> pArray(new int[4]);
/// p[0] = 4;
///
/// Type completeness requirements
/// http://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t/6089065#6089065
/// Here is a table which documents several members of shared_ptr and unique_ptr with respect to completeness requirements.
/// If the member requires a complete type, the entry has a "C", otherwise the table entry is filled with "I".
///
/// unique_ptr shared_ptr
/// +------------------------+---------------+---------------+
/// | P() | I | I |
/// | default constructor | | |
/// +------------------------+---------------+---------------+
/// | P(const P&) | N/A | I |
/// | copy constructor | | |
/// +------------------------+---------------+---------------+
/// | P(P&&) | I | I |
/// | move constructor | | |
/// +------------------------+---------------+---------------+
/// | ~P() | C | I |
/// | destructor | | |
/// +------------------------+---------------+---------------+
/// | P(A*) | I | C |
/// +------------------------+---------------+---------------+
/// | operator=(const P&) | N/A | I |
/// | copy assignment | | |
/// +------------------------+---------------+---------------+
/// | operator=(P&&) | C | I |
/// | move assignment | | |
/// +------------------------+---------------+---------------+
/// | reset() | C | I |
/// +------------------------+---------------+---------------+
/// | reset(A*) | C | C |
/// +------------------------+---------------+---------------+
///
template <typename T, typename Deleter = eastl::default_delete<T> >
class unique_ptr
{
static_assert(!is_rvalue_reference<Deleter>::value, "The supplied Deleter cannot be a r-value reference.");
public:
typedef Deleter deleter_type;
typedef T element_type;
typedef unique_ptr<element_type, deleter_type> this_type;
typedef typename Internal::unique_pointer_type<element_type, deleter_type>::type pointer;
public:
/// unique_ptr
/// Construct a unique_ptr from a pointer allocated via new.
/// Example usage:
/// unique_ptr<int> ptr;
EA_CPP14_CONSTEXPR unique_ptr() EASTL_NOEXCEPT
: mPair(pointer())
{
static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class.");
}
/// unique_ptr
/// Construct a unique_ptr from a null pointer.
/// Example usage:
/// unique_ptr<int> ptr(nullptr);
EA_CPP14_CONSTEXPR unique_ptr(std::nullptr_t) EASTL_NOEXCEPT
: mPair(pointer())
{
static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class.");
}
/// unique_ptr
/// Construct a unique_ptr from a pointer allocated via new.
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
explicit unique_ptr(pointer pValue) EASTL_NOEXCEPT
: mPair(pValue)
{
static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class.");
}
/// unique_ptr
/// Constructs a unique_ptr with the owner pointer and deleter specified
/// Example usage:
/// eastl::smart_ptr_deleter<int> del;
/// unique_ptr<int> ptr(new int(3), del);
unique_ptr(pointer pValue, typename eastl::conditional<eastl::is_lvalue_reference<deleter_type>::value, deleter_type, typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter) EASTL_NOEXCEPT
: mPair(pValue, deleter) {}
/// unique_ptr
/// Constructs a unique_ptr with the owned pointer and deleter specified (rvalue)
/// Example usage:
/// unique_ptr<int> ptr(new int(3), eastl::smart_ptr_deleter<int>());
unique_ptr(pointer pValue, typename eastl::remove_reference<deleter_type>::type&& deleter) EASTL_NOEXCEPT
: mPair(pValue, eastl::move(deleter))
{
static_assert(!eastl::is_lvalue_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
}
/// unique_ptr
/// Move constructor
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// unique_ptr<int> newPtr = eastl::move(ptr);
unique_ptr(this_type&& x) EASTL_NOEXCEPT
: mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {}
/// unique_ptr
/// Move constructor
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// unique_ptr<int> newPtr = eastl::move(ptr);
template <typename U, typename E>
unique_ptr(unique_ptr<U, E>&& u, typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_convertible<E, deleter_type>::value && (is_same<deleter_type, E>::value || !is_lvalue_reference<deleter_type>::value)>::type* = 0) EASTL_NOEXCEPT
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
/// unique_ptr
/// Move assignment
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// unique_ptr<int> newPtr(new int(4));
/// ptr = eastl::move(newPtr); // Deletes int(3) and assigns mpValue to int(4)
this_type& operator=(this_type&& x) EASTL_NOEXCEPT
{
reset(x.release());
mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter()));
return *this;
}
/// unique_ptr
/// Move assignment
template <typename U, typename E>
typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type
operator=(unique_ptr<U, E>&& u) EASTL_NOEXCEPT
{
reset(u.release());
mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter()));
return *this;
}
/// operator=(nullptr_t)
this_type& operator=(std::nullptr_t) EASTL_NOEXCEPT
{
reset();
return *this;
}
/// ~unique_ptr
/// Destroys the owned pointer. The destructor for the object
/// referred to by the owned pointer will be called.
~unique_ptr() EASTL_NOEXCEPT
{
reset();
}
/// reset
/// Deletes the owned pointer and takes ownership of the
/// passed in pointer. If the passed in pointer is the same
/// as the owned pointer, nothing is done.
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// ptr.reset(new int(4)); // deletes int(3)
/// ptr.reset(NULL); // deletes int(4)
void reset(pointer pValue = pointer()) EASTL_NOEXCEPT
{
if (pValue != mPair.first())
{
if (auto first = eastl::exchange(mPair.first(), pValue))
get_deleter()(first);
}
}
/// release
/// This simply forgets the owned pointer. It doesn't
/// free it but rather assumes that the user does.
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// int* pInt = ptr.release();
/// delete pInt;
pointer release() EASTL_NOEXCEPT
{
pointer const pTemp = mPair.first();
mPair.first() = pointer();
return pTemp;
}
/// detach
/// For backwards-compatibility with pre-C++11 code.
pointer detach() EASTL_NOEXCEPT { return release(); }
/// swap
/// Exchanges the owned pointer beween two unique_ptr objects.
void swap(this_type& x) EASTL_NOEXCEPT
{
mPair.swap(x.mPair);
}
/// operator*
/// Returns the owner pointer dereferenced.
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// int x = *ptr;
typename add_lvalue_reference<T>::type operator*() const // Not noexcept, because the pointer may be NULL.
{
return *mPair.first();
}
/// operator->
/// Allows access to the owned pointer via operator->()
/// Example usage:
/// struct X{ void DoSomething(); };
/// unique_ptr<int> ptr(new X);
/// ptr->DoSomething();
pointer operator->() const EASTL_NOEXCEPT
{
return mPair.first();
}
/// get
/// Returns the owned pointer. Note that this class does
/// not provide an operator T() function. This is because such
/// a thing (automatic conversion) is deemed unsafe.
/// Example usage:
/// struct X{ void DoSomething(); };
/// unique_ptr<int> ptr(new X);
/// X* pX = ptr.get();
/// pX->DoSomething();
pointer get() const EASTL_NOEXCEPT
{
return mPair.first();
}
/// get_deleter
/// Returns the deleter used to delete the owned pointer
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// eastl::smart_ptr_deleter<int>& del = ptr.get_deleter();
deleter_type& get_deleter() EASTL_NOEXCEPT
{
return mPair.second();
}
/// get_deleter
/// Const version for getting the deleter
const deleter_type& get_deleter() const EASTL_NOEXCEPT
{
return mPair.second();
}
#ifdef EA_COMPILER_NO_EXPLICIT_CONVERSION_OPERATORS
/// Note that below we do not use operator bool(). The reason for this
/// is that booleans automatically convert up to short, int, float, etc.
/// The result is that this: if(uniquePtr == 1) would yield true (bad).
typedef T* (this_type::*bool_)() const;
operator bool_() const EASTL_NOEXCEPT
{
if(mPair.first())
return &this_type::get;
return NULL;
}
bool operator!() const EASTL_NOEXCEPT
{
return (mPair.first() == pointer());
}
#else
/// operator bool
/// Allows for using a unique_ptr as a boolean.
/// Example usage:
/// unique_ptr<int> ptr(new int(3));
/// if(ptr)
/// ++*ptr;
///
explicit operator bool() const EASTL_NOEXCEPT
{
return (mPair.first() != pointer());
}
#endif
/// These functions are deleted in order to prevent copying, for safety.
unique_ptr(const this_type&) = delete;
unique_ptr& operator=(const this_type&) = delete;
unique_ptr& operator=(pointer pValue) = delete;
protected:
eastl::compressed_pair<pointer, deleter_type> mPair;
}; // class unique_ptr
/// unique_ptr specialization for unbounded arrays.
///
/// Differences from unique_ptr<T>:
/// - Conversions between different types of unique_ptr<T[], D> or to or
/// from the non-array forms of unique_ptr produce an ill-formed program.
/// - Pointers to types derived from T are rejected by the constructors, and by reset.
/// - The observers operator* and operator-> are not provided.
/// - The indexing observer operator[] is provided.
/// - The default deleter will call delete[].
///
/// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]).
///
/// Example usage:
/// unique_ptr<int[]> ptr(new int[10]);
/// ptr[4] = 4;
///
template <typename T, typename Deleter>
class unique_ptr<T[], Deleter>
{
public:
typedef Deleter deleter_type;
typedef T element_type;
typedef unique_ptr<element_type[], deleter_type> this_type;
typedef typename Internal::unique_pointer_type<element_type, deleter_type>::type pointer;
public:
EA_CPP14_CONSTEXPR unique_ptr() EASTL_NOEXCEPT
: mPair(pointer())
{
static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class.");
}
EA_CPP14_CONSTEXPR unique_ptr(std::nullptr_t) EASTL_NOEXCEPT
: mPair(pointer())
{
static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class.");
}
template <typename P,
typename = eastl::enable_if_t<Internal::is_array_cv_convertible<P, pointer>::value>> // Pointers to types derived from T are rejected by the constructors, and by reset.
explicit unique_ptr(P pArray) EASTL_NOEXCEPT
: mPair(pArray)
{
static_assert(!eastl::is_pointer<deleter_type>::value,
"unique_ptr deleter default-constructed with null pointer. Use a different constructor or "
"change your deleter to a class.");
}
template <typename P>
unique_ptr(P pArray, typename eastl::conditional<eastl::is_lvalue_reference<deleter_type>::value, deleter_type,
typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter,
typename eastl::enable_if<Internal::is_array_cv_convertible<P, pointer>::value>::type* = 0) EASTL_NOEXCEPT
: mPair(pArray, deleter) {}
template <typename P>
unique_ptr(P pArray, typename eastl::remove_reference<deleter_type>::type&& deleter, eastl::enable_if_t<Internal::is_array_cv_convertible<P, pointer>::value>* = 0) EASTL_NOEXCEPT
: mPair(pArray, eastl::move(deleter))
{
static_assert(!eastl::is_lvalue_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
}
unique_ptr(this_type&& x) EASTL_NOEXCEPT
: mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {}
template <typename U, typename E>
unique_ptr(unique_ptr<U, E>&& u, typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value &&
eastl::is_convertible<E, deleter_type>::value &&
(!eastl::is_lvalue_reference<deleter_type>::value || eastl::is_same<E, deleter_type>::value)>::type* = 0) EASTL_NOEXCEPT
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
this_type& operator=(this_type&& x) EASTL_NOEXCEPT
{
reset(x.release());
mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter()));
return *this;
}
template <typename U, typename E>
typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type
operator=(unique_ptr<U, E>&& u) EASTL_NOEXCEPT
{
reset(u.release());
mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter()));
return *this;
}
this_type& operator=(std::nullptr_t) EASTL_NOEXCEPT
{
reset();
return *this;
}
~unique_ptr() EASTL_NOEXCEPT
{
reset();
}
void reset(pointer pArray = pointer()) EASTL_NOEXCEPT
{
if(pArray != mPair.first())
{
if (auto first = eastl::exchange(mPair.first(), pArray))
get_deleter()(first);
}
}
pointer release() EASTL_NOEXCEPT
{
pointer const pTemp = mPair.first();
mPair.first() = pointer();
return pTemp;
}
/// detach
/// For backwards-compatibility with pre-C++11 code.
pointer detach() EASTL_NOEXCEPT { return release(); }
void swap(this_type& x) EASTL_NOEXCEPT
{
mPair.swap(x.mPair);
}
/// operator[]
/// Returns a reference to the specified item in the owned pointer
/// array.
/// Example usage:
/// unique_ptr<int> ptr(new int[6]);
/// int x = ptr[2];
typename add_lvalue_reference<T>::type operator[](ptrdiff_t i) const
{
// assert(mpArray && (i >= 0));
return mPair.first()[i];
}
pointer get() const EASTL_NOEXCEPT
{
return mPair.first();
}
deleter_type& get_deleter() EASTL_NOEXCEPT
{
return mPair.second();
}
const deleter_type& get_deleter() const EASTL_NOEXCEPT
{
return mPair.second();
}
#ifdef EA_COMPILER_NO_EXPLICIT_CONVERSION_OPERATORS
typedef T* (this_type::*bool_)() const;
operator bool_() const EASTL_NOEXCEPT
{
if(mPair.first())
return &this_type::get;
return NULL;
}
bool operator!() const EASTL_NOEXCEPT
{
return (mPair.first() == pointer());
}
#else
explicit operator bool() const EASTL_NOEXCEPT
{
return (mPair.first() != pointer());
}
#endif
/// These functions are deleted in order to prevent copying, for safety.
unique_ptr(const this_type&) = delete;
unique_ptr& operator=(const this_type&) = delete;
unique_ptr& operator=(pointer pArray) = delete;
protected:
eastl::compressed_pair<pointer, deleter_type> mPair;
};
/// make_unique
///
/// The C++11 Standard doesn't have make_unique, but there's no agreed reason as to why.
/// http://stackoverflow.com/questions/12580432/why-does-c11-have-make-shared-but-not-make-unique
/// http://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/
/// Herb's solution is OK but doesn't support unique_ptr<[]> (array version). We do the same
/// thing libc++ does and make a specialization of make_unique for arrays.
///
/// make_unique has two cases where you can't use it and need to directly use unique_ptr:
/// - You need to construct the unique_ptr with a raw pointer.
/// - You need to specify a custom deleter.
///
/// Note: This function uses global new T by default to create the ptr instance, as per
/// the C++11 Standard make_shared_ptr.
///
/// Example usage:
/// struct Test{ Test(int, int){} };
/// auto p = make_unique<Test>(1, 2);
///
/// auto pArray = make_unique<Test[]>(4);
///
template <typename T, typename... Args>
inline typename eastl::enable_if<!eastl::is_array<T>::value, eastl::unique_ptr<T>>::type make_unique(Args&&... args)
{ return unique_ptr<T>(new T(eastl::forward<Args>(args)...)); }
template <typename T>
inline typename eastl::enable_if<eastl::is_unbounded_array<T>::value, eastl::unique_ptr<T>>::type make_unique(size_t n)
{
typedef typename eastl::remove_extent<T>::type TBase;
return unique_ptr<T>(new TBase[n]);
}
// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]).
template <typename T, typename... Args>
typename eastl::enable_if<eastl::is_bounded_array<T>::value>::type
make_unique(Args&&...) = delete;
/// hash specialization for unique_ptr.
/// It simply returns eastl::hash(x.get()). If your unique_ptr pointer type (the return value of unique_ptr<T>::get) is
/// a custom type and not a built-in pointer type then you will need to independently define eastl::hash for that type.
template <typename T, typename D>
struct hash< unique_ptr<T, D> >
{
size_t operator()(const unique_ptr<T, D>& x) const EASTL_NOEXCEPT
{ return eastl::hash<typename unique_ptr<T, D>::pointer>()(x.get()); }
};
/// swap
/// Exchanges the owned pointer beween two unique_ptr objects.
/// This non-member version is useful for compatibility of unique_ptr
/// objects with the C++ Standard Library and other libraries.
template <typename T, typename D>
inline void swap(unique_ptr<T, D>& a, unique_ptr<T, D>& b) EASTL_NOEXCEPT
{
a.swap(b);
}
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator==(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return (a.get() == b.get());
}
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename T1, typename D1, typename T2, typename D2>
requires std::three_way_comparable_with<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer>
inline std::compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> operator<=>(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return a.get() <=> b.get();
}
#else
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator!=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return !(a.get() == b.get());
}
#endif
/// Returns which unique_ptr is 'less' than the other. Useful when storing
/// sorted containers of unique_ptr objects.
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator<(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
//typedef typename eastl::unique_ptr<T1, D1>::pointer P1; // We currently need to make these temporary variables, as otherwise clang complains about CPointer being int*&&&.
//typedef typename eastl::unique_ptr<T2, D2>::pointer P2; // I think there's something wrong with our common_type type trait implementation.
//typedef typename eastl::common_type<P1, P2>::type PCommon; // "in instantiation of function template specialization 'eastl::operator<<int, int>, no known conversion from 'element_type *' (aka 'int *') to 'int *&&&' for 1st argument"
//return less<PCommon>()(a.get(), b.get()); // It looks like common_type is making CPointer be (e.g.) int*&& instead of int*, though the problem may be in how less<> deals with that.
typedef typename eastl::unique_ptr<T1, D1>::pointer P1;
typedef typename eastl::unique_ptr<T2, D2>::pointer P2;
typedef typename eastl::common_type<P1, P2>::type PCommon;
PCommon pT1 = a.get();
PCommon pT2 = b.get();
return less<PCommon>()(pT1, pT2);
}
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator>(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return (b < a);
}
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator<=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return !(b < a);
}
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator>=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return !(a < b);
}
template <typename T, typename D>
inline bool operator==(const unique_ptr<T, D>& a, std::nullptr_t) EASTL_NOEXCEPT
{
return !a;
}
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename T, typename D>
requires std::three_way_comparable_with<typename unique_ptr<T, D>::pointer, std::nullptr_t>
inline std::compare_three_way_result_t<typename unique_ptr<T, D>::pointer, std::nullptr_t> operator<=>(const unique_ptr<T, D>& a, std::nullptr_t)
{
return a.get() <=> nullptr;
}
#else
template <typename T, typename D>
inline bool operator==(std::nullptr_t, const unique_ptr<T, D>& a) EASTL_NOEXCEPT
{
return !a;
}
template <typename T, typename D>
inline bool operator!=(const unique_ptr<T, D>& a, std::nullptr_t) EASTL_NOEXCEPT
{
return static_cast<bool>(a);
}
template <typename T, typename D>
inline bool operator!=(std::nullptr_t, const unique_ptr<T, D>& a) EASTL_NOEXCEPT
{
return static_cast<bool>(a);
}
#endif
template <typename T, typename D>
inline bool operator<(const unique_ptr<T, D>& a, std::nullptr_t)
{
typedef typename unique_ptr<T, D>::pointer pointer;
return less<pointer>()(a.get(), nullptr);
}
template <typename T, typename D>
inline bool operator<(std::nullptr_t, const unique_ptr<T, D>& b)
{
typedef typename unique_ptr<T, D>::pointer pointer;
pointer pT = b.get();
return less<pointer>()(nullptr, pT);
}
template <typename T, typename D>
inline bool operator>(const unique_ptr<T, D>& a, std::nullptr_t)
{
return (nullptr < a);
}
template <typename T, typename D>
inline bool operator>(std::nullptr_t, const unique_ptr<T, D>& b)
{
return (b < nullptr);
}
template <typename T, typename D>
inline bool operator<=(const unique_ptr<T, D>& a, std::nullptr_t)
{
return !(nullptr < a);
}
template <typename T, typename D>
inline bool operator<=(std::nullptr_t, const unique_ptr<T, D>& b)
{
return !(b < nullptr);
}
template <typename T, typename D>
inline bool operator>=(const unique_ptr<T, D>& a, std::nullptr_t)
{
return !(a < nullptr);
}
template <typename T, typename D>
inline bool operator>=(std::nullptr_t, const unique_ptr<T, D>& b)
{
return !(nullptr < b);
}
} // namespace eastl
#endif // Header include guard