2 * Copyright 2008-2012 NVIDIA Corporation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 /*! \file device_reference.h
19 * \brief A reference to a variable which resides in the "device" system's memory space
24 #include <thrust/detail/config.h>
25 #include <thrust/device_ptr.h>
26 #include <thrust/detail/type_traits.h>
27 #include <thrust/detail/reference.h>
32 /*! \addtogroup memory_management_classes Memory Management Classes
33 * \ingroup memory_management
37 /*! \p device_reference acts as a reference-like object to an object stored in device memory.
38 * \p device_reference is not intended to be used directly; rather, this type
39 * is the result of deferencing a \p device_ptr. Similarly, taking the address of
40 * a \p device_reference yields a \p device_ptr.
42 * \p device_reference may often be used from host code in place of operations defined on
43 * its associated \c value_type. For example, when \p device_reference refers to an
44 * arithmetic type, arithmetic operations on it are legal:
47 * #include <thrust/device_vector.h>
51 * thrust::device_vector<int> vec(1, 13);
53 * thrust::device_reference<int> ref_to_thirteen = vec[0];
55 * int x = ref_to_thirteen + 1;
63 * Similarly, we can print the value of \c ref_to_thirteen in the above code by using an
67 * #include <thrust/device_vector.h>
72 * thrust::device_vector<int> vec(1, 13);
74 * thrust::device_reference<int> ref_to_thirteen = vec[0];
76 * std::cout << ref_to_thirteen << std::endl;
84 * Of course, we needn't explicitly create a \p device_reference in the previous
85 * example, because one is returned by \p device_vector's bracket operator. A more natural
86 * way to print the value of a \p device_vector element might be:
89 * #include <thrust/device_vector.h>
94 * thrust::device_vector<int> vec(1, 13);
96 * std::cout << vec[0] << std::endl;
104 * These kinds of operations should be used sparingly in performance-critical code, because
105 * they imply a potentially expensive copy between host and device space.
107 * Some operations which are possible with regular objects are impossible with their
108 * corresponding \p device_reference objects due to the requirements of the C++ language. For
109 * example, because the member access operator cannot be overloaded, member variables and functions
110 * of a referent object cannot be directly accessed through its \p device_reference.
112 * The following code, which generates a compiler error, illustrates:
115 * #include <thrust/device_vector.h>
124 * thrust::device_vector<foo> foo_vec(1);
126 * thrust::device_reference<foo> foo_ref = foo_vec[0];
128 * foo_ref.x = 13; // ERROR: x cannot be accessed through foo_ref
134 * Instead, a host space copy must be created to access \c foo's \c x member:
137 * #include <thrust/device_vector.h>
146 * thrust::device_vector<foo> foo_vec(1);
148 * // create a local host-side foo object
152 * thrust::device_reference<foo> foo_ref = foo_vec[0];
154 * foo_ref = host_foo;
156 * // foo_ref's x member is 13
162 * Another common case where a \p device_reference cannot directly be used in place of
163 * its referent object occurs when passing them as parameters to functions like \c printf
164 * which have varargs parameters. Because varargs parameters must be Plain Old Data, a
165 * \p device_reference to a POD type requires a cast when passed to \c printf:
169 * #include <thrust/device_vector.h>
173 * thrust::device_vector<int> vec(1,13);
175 * // vec[0] must be cast to int when passing to printf
176 * printf("%d\n", (int) vec[0]);
186 class device_reference
187 : public thrust::reference<
189 thrust::device_ptr<T>,
190 thrust::device_reference<T>
194 typedef thrust::reference<
196 thrust::device_ptr<T>,
197 thrust::device_reference<T>
201 /*! The type of the value referenced by this type of \p device_reference.
203 typedef typename super_t::value_type value_type;
205 /*! The type of the expression <tt>&ref</tt>, where <tt>ref</tt> is a \p device_reference.
207 typedef typename super_t::pointer pointer;
209 /*! This copy constructor accepts a const reference to another
210 * \p device_reference. After this \p device_reference is constructed,
211 * it shall refer to the same object as \p other.
213 * \param other A \p device_reference to copy from.
215 * The following code snippet demonstrates the semantics of this
219 * #include <thrust/device_vector.h>
220 * #include <assert.h>
222 * thrust::device_vector<int> v(1,0);
223 * thrust::device_reference<int> ref = v[0];
225 * // ref equals the object at v[0]
226 * assert(ref == v[0]);
228 * // the address of ref equals the address of v[0]
229 * assert(&ref == &v[0]);
231 * // modifying v[0] modifies ref
236 * \note This constructor is templated primarily to allow initialization of
237 * <tt>device_reference<const T></tt> from <tt>device_reference<T></tt>.
239 template<typename OtherT>
241 device_reference(const device_reference<OtherT> &other,
242 typename thrust::detail::enable_if_convertible<
243 typename device_reference<OtherT>::pointer,
249 /*! This copy constructor initializes this \p device_reference
250 * to refer to an object pointed to by the given \p device_ptr. After
251 * this \p device_reference is constructed, it shall refer to the
252 * object pointed to by \p ptr.
254 * \param ptr A \p device_ptr to copy from.
256 * The following code snippet demonstrates the semantic of this
260 * #include <thrust/device_vector.h>
261 * #include <assert.h>
263 * thrust::device_vector<int> v(1,0);
264 * thrust::device_ptr<int> ptr = &v[0];
265 * thrust::device_reference<int> ref(ptr);
267 * // ref equals the object pointed to by ptr
268 * assert(ref == *ptr);
270 * // the address of ref equals ptr
271 * assert(&ref == ptr);
273 * // modifying *ptr modifies ref
279 explicit device_reference(const pointer &ptr)
283 /*! This assignment operator assigns the value of the object referenced by
284 * the given \p device_reference to the object referenced by this
285 * \p device_reference.
287 * \param other The \p device_reference to assign from.
288 * \return <tt>*this</tt>
290 template<typename OtherT>
292 device_reference &operator=(const device_reference<OtherT> &other);
294 /*! Assignment operator assigns the value of the given value to the
295 * value referenced by this \p device_reference.
297 * \param x The value to assign from.
298 * \return <tt>*this</tt>
301 device_reference &operator=(const value_type &x);
303 // declare these members for the purpose of Doxygenating them
304 // they actually exist in a derived-from class
306 /*! Address-of operator returns a \p device_ptr pointing to the object
307 * referenced by this \p device_reference. It does not return the
308 * address of this \p device_reference.
310 * \return A \p device_ptr pointing to the object this
311 * \p device_reference references.
314 pointer operator&(void) const;
316 /*! Conversion operator converts this \p device_reference to T
317 * by returning a copy of the object referenced by this
318 * \p device_reference.
320 * \return A copy of the object referenced by this \p device_reference.
323 operator value_type (void) const;
325 /*! swaps the value this \p device_reference references with another.
326 * \p other The other \p device_reference with which to swap.
329 void swap(device_reference &other);
331 /*! Prefix increment operator increments the object referenced by this
332 * \p device_reference.
334 * \return <tt>*this</tt>
336 * The following code snippet demonstrates the semantics of
337 * \p device_reference's prefix increment operator.
340 * #include <thrust/device_vector.h>
341 * #include <assert.h>
343 * thrust::device_vector<int> v(1,0);
344 * thrust::device_ptr<int> ptr = &v[0];
345 * thrust::device_reference<int> ref(ptr);
350 * // the object pointed to by ptr equals 1
362 * // the object pointed to by ptr equals 1
369 * \note The increment executes as if it were executed on the host.
370 * This may change in a later version.
372 device_reference &operator++(void);
374 /*! Postfix increment operator copies the object referenced by this
375 * \p device_reference, increments the object referenced by this
376 * \p device_reference, and returns the copy.
378 * \return A copy of the object referenced by this \p device_reference
379 * before being incremented.
381 * The following code snippet demonstrates the semantics of
382 * \p device_reference's postfix increment operator.
385 * #include <thrust/device_vector.h>
386 * #include <assert.h>
388 * thrust::device_vector<int> v(1,0);
389 * thrust::device_ptr<int> ptr = &v[0];
390 * thrust::device_reference<int> ref(ptr);
395 * // the object pointed to by ptr equals 0
410 * // the object pointed to by ptr equals 1
417 * \note The increment executes as if it were executed on the host.
418 * This may change in a later version.
420 value_type operator++(int);
422 /*! Addition assignment operator add-assigns the object referenced by this
423 * \p device_reference and returns this \p device_reference.
425 * \param rhs The right hand side of the add-assignment.
426 * \return <tt>*this</tt>.
428 * The following code snippet demonstrates the semantics of
429 * \p device_reference's addition assignment operator.
432 * #include <thrust/device_vector.h>
433 * #include <assert.h>
435 * thrust::device_vector<int> v(1,0);
436 * thrust::device_ptr<int> ptr = &v[0];
437 * thrust::device_reference<int> ref(ptr);
442 * // the object pointed to by ptr equals 0
454 * // the object pointed to by ptr equals 5
461 * \note The add-assignment executes as as if it were executed on the host.
462 * This may change in a later version.
464 device_reference &operator+=(const T &rhs);
466 /*! Prefix decrement operator decrements the object referenced by this
467 * \p device_reference.
469 * \return <tt>*this</tt>
471 * The following code snippet demonstrates the semantics of
472 * \p device_reference's prefix decrement operator.
475 * #include <thrust/device_vector.h>
476 * #include <assert.h>
478 * thrust::device_vector<int> v(1,0);
479 * thrust::device_ptr<int> ptr = &v[0];
480 * thrust::device_reference<int> ref(ptr);
485 * // the object pointed to by ptr equals 0
497 * // the object pointed to by ptr equals -1
498 * assert(*ptr == -1);
501 * assert(v[0] == -1);
504 * \note The decrement executes as if it were executed on the host.
505 * This may change in a later version.
507 device_reference &operator--(void);
509 /*! Postfix decrement operator copies the object referenced by this
510 * \p device_reference, decrements the object referenced by this
511 * \p device_reference, and returns the copy.
513 * \return A copy of the object referenced by this \p device_reference
514 * before being decremented.
516 * The following code snippet demonstrates the semantics of
517 * \p device_reference's postfix decrement operator.
520 * #include <thrust/device_vector.h>
521 * #include <assert.h>
523 * thrust::device_vector<int> v(1,0);
524 * thrust::device_ptr<int> ptr = &v[0];
525 * thrust::device_reference<int> ref(ptr);
530 * // the object pointed to by ptr equals 0
545 * // the object pointed to by ptr equals -1
546 * assert(*ptr == -1);
549 * assert(v[0] == -1);
552 * \note The decrement executes as if it were executed on the host.
553 * This may change in a later version.
555 value_type operator--(int);
557 /*! Subtraction assignment operator subtract-assigns the object referenced by this
558 * \p device_reference and returns this \p device_reference.
560 * \param rhs The right hand side of the subtraction-assignment.
561 * \return <tt>*this</tt>.
563 * The following code snippet demonstrates the semantics of
564 * \p device_reference's addition assignment operator.
567 * #include <thrust/device_vector.h>
568 * #include <assert.h>
570 * thrust::device_vector<int> v(1,0);
571 * thrust::device_ptr<int> ptr = &v[0];
572 * thrust::device_reference<int> ref(ptr);
577 * // the object pointed to by ptr equals 0
583 * // subtract-assign ref
589 * // the object pointed to by ptr equals -5
590 * assert(*ptr == -5);
593 * assert(v[0] == -5);
596 * \note The subtract-assignment executes as as if it were executed on the host.
597 * This may change in a later version.
599 device_reference &operator-=(const T &rhs);
601 /*! Multiplication assignment operator multiply-assigns the object referenced by this
602 * \p device_reference and returns this \p device_reference.
604 * \param rhs The right hand side of the multiply-assignment.
605 * \return <tt>*this</tt>.
607 * The following code snippet demonstrates the semantics of
608 * \p device_reference's multiply assignment operator.
611 * #include <thrust/device_vector.h>
612 * #include <assert.h>
614 * thrust::device_vector<int> v(1,1);
615 * thrust::device_ptr<int> ptr = &v[0];
616 * thrust::device_reference<int> ref(ptr);
621 * // the object pointed to by ptr equals 1
627 * // multiply-assign ref
633 * // the object pointed to by ptr equals 5
640 * \note The multiply-assignment executes as as if it were executed on the host.
641 * This may change in a later version.
643 device_reference &operator*=(const T &rhs);
645 /*! Division assignment operator divide-assigns the object referenced by this
646 * \p device_reference and returns this \p device_reference.
648 * \param rhs The right hand side of the divide-assignment.
649 * \return <tt>*this</tt>.
651 * The following code snippet demonstrates the semantics of
652 * \p device_reference's divide assignment operator.
655 * #include <thrust/device_vector.h>
656 * #include <assert.h>
658 * thrust::device_vector<int> v(1,5);
659 * thrust::device_ptr<int> ptr = &v[0];
660 * thrust::device_reference<int> ref(ptr);
665 * // the object pointed to by ptr equals 5
671 * // divide-assign ref
677 * // the object pointed to by ptr equals 1
684 * \note The divide-assignment executes as as if it were executed on the host.
685 * This may change in a later version.
687 device_reference &operator/=(const T &rhs);
689 /*! Modulation assignment operator modulus-assigns the object referenced by this
690 * \p device_reference and returns this \p device_reference.
692 * \param rhs The right hand side of the divide-assignment.
693 * \return <tt>*this</tt>.
695 * The following code snippet demonstrates the semantics of
696 * \p device_reference's divide assignment operator.
699 * #include <thrust/device_vector.h>
700 * #include <assert.h>
702 * thrust::device_vector<int> v(1,5);
703 * thrust::device_ptr<int> ptr = &v[0];
704 * thrust::device_reference<int> ref(ptr);
709 * // the object pointed to by ptr equals 5
715 * // modulus-assign ref
721 * // the object pointed to by ptr equals 0
728 * \note The modulus-assignment executes as as if it were executed on the host.
729 * This may change in a later version.
731 device_reference &operator%=(const T &rhs);
733 /*! Bitwise left shift assignment operator left shift-assigns the object referenced by this
734 * \p device_reference and returns this \p device_reference.
736 * \param rhs The right hand side of the left shift-assignment.
737 * \return <tt>*this</tt>.
739 * The following code snippet demonstrates the semantics of
740 * \p device_reference's left shift assignment operator.
743 * #include <thrust/device_vector.h>
744 * #include <assert.h>
746 * thrust::device_vector<int> v(1,1);
747 * thrust::device_ptr<int> ptr = &v[0];
748 * thrust::device_reference<int> ref(ptr);
753 * // the object pointed to by ptr equals 1
759 * // left shift-assign ref
765 * // the object pointed to by ptr equals 2
772 * \note The left shift-assignment executes as as if it were executed on the host.
773 * This may change in a later version.
775 device_reference &operator<<=(const T &rhs);
777 /*! Bitwise right shift assignment operator right shift-assigns the object referenced by this
778 * \p device_reference and returns this \p device_reference.
780 * \param rhs The right hand side of the right shift-assignment.
781 * \return <tt>*this</tt>.
783 * The following code snippet demonstrates the semantics of
784 * \p device_reference's right shift assignment operator.
787 * #include <thrust/device_vector.h>
788 * #include <assert.h>
790 * thrust::device_vector<int> v(1,2);
791 * thrust::device_ptr<int> ptr = &v[0];
792 * thrust::device_reference<int> ref(ptr);
797 * // the object pointed to by ptr equals 2
803 * // right shift-assign ref
809 * // the object pointed to by ptr equals 1
816 * \note The right shift-assignment executes as as if it were executed on the host.
817 * This may change in a later version.
819 device_reference &operator>>=(const T &rhs);
821 /*! Bitwise AND assignment operator AND-assigns the object referenced by this
822 * \p device_reference and returns this \p device_reference.
824 * \param rhs The right hand side of the AND-assignment.
825 * \return <tt>*this</tt>.
827 * The following code snippet demonstrates the semantics of
828 * \p device_reference's AND assignment operator.
831 * #include <thrust/device_vector.h>
832 * #include <assert.h>
834 * thrust::device_vector<int> v(1,1);
835 * thrust::device_ptr<int> ptr = &v[0];
836 * thrust::device_reference<int> ref(ptr);
841 * // the object pointed to by ptr equals 1
847 * // right AND-assign ref
853 * // the object pointed to by ptr equals 0
860 * \note The AND-assignment executes as as if it were executed on the host.
861 * This may change in a later version.
863 device_reference &operator&=(const T &rhs);
865 /*! Bitwise OR assignment operator OR-assigns the object referenced by this
866 * \p device_reference and returns this \p device_reference.
868 * \param rhs The right hand side of the OR-assignment.
869 * \return <tt>*this</tt>.
871 * The following code snippet demonstrates the semantics of
872 * \p device_reference's OR assignment operator.
875 * #include <thrust/device_vector.h>
876 * #include <assert.h>
878 * thrust::device_vector<int> v(1,0);
879 * thrust::device_ptr<int> ptr = &v[0];
880 * thrust::device_reference<int> ref(ptr);
885 * // the object pointed to by ptr equals 0
891 * // right OR-assign ref
897 * // the object pointed to by ptr equals 1
904 * \note The OR-assignment executes as as if it were executed on the host.
905 * This may change in a later version.
907 device_reference &operator|=(const T &rhs);
909 /*! Bitwise XOR assignment operator XOR-assigns the object referenced by this
910 * \p device_reference and returns this \p device_reference.
912 * \param rhs The right hand side of the XOR-assignment.
913 * \return <tt>*this</tt>.
915 * The following code snippet demonstrates the semantics of
916 * \p device_reference's XOR assignment operator.
919 * #include <thrust/device_vector.h>
920 * #include <assert.h>
922 * thrust::device_vector<int> v(1,1);
923 * thrust::device_ptr<int> ptr = &v[0];
924 * thrust::device_reference<int> ref(ptr);
929 * // the object pointed to by ptr equals 1
935 * // right XOR-assign ref
941 * // the object pointed to by ptr equals 0
948 * \note The XOR-assignment executes as as if it were executed on the host.
949 * This may change in a later version.
951 device_reference &operator^=(const T &rhs);
952 #endif // end doxygen-only members
953 }; // end device_reference
955 /*! swaps the value of one \p device_reference with another.
956 * \p x The first \p device_reference of interest.
957 * \p y The second \p device_reference of interest.
961 void swap(device_reference<T> &x, device_reference<T> &y);
968 #include <thrust/detail/device_reference.inl>