36 #include <type_traits>
43 inline namespace _V1 {
49 template <
int dimensions>
class range;
51 template <
typename DataT>
54 template <
typename DataT,
int Dimensions, access::mode AccessMode>
57 template <
typename T,
int Dimensions,
typename AllocatorT,
typename Enable>
60 namespace ext::oneapi {
68 template <
typename T,
int Dimensions,
typename AllocatorT>
71 const event &Evt,
bool OwnNativeHandle =
true) {
90 std::unique_ptr<detail::SYCLMemObjAllocator> Allocator);
92 buffer_plain(
void *HostData,
size_t SizeInBytes,
size_t RequiredAlign,
94 std::unique_ptr<detail::SYCLMemObjAllocator> Allocator);
96 buffer_plain(
const void *HostData,
size_t SizeInBytes,
size_t RequiredAlign,
98 std::unique_ptr<detail::SYCLMemObjAllocator> Allocator);
100 buffer_plain(
const std::shared_ptr<const void> &HostData,
101 const size_t SizeInBytes,
size_t RequiredAlign,
103 std::unique_ptr<detail::SYCLMemObjAllocator> Allocator,
109 const size_t SizeInBytes,
size_t RequiredAlign,
111 std::unique_ptr<detail::SYCLMemObjAllocator> Allocator,
115 std::unique_ptr<detail::SYCLMemObjAllocator> Allocator,
116 bool OwnNativeHandle,
const event &AvailableEvent);
118 buffer_plain(
const std::shared_ptr<detail::buffer_impl> &impl) : impl(impl) {}
120 void set_final_data_internal();
122 void set_final_data_internal(
123 const std::function<
void(
const std::function<
void(
void *
const Ptr)> &)>
126 void set_write_back(
bool NeedWriteBack);
129 void *UserObj,
const void *HostObj,
130 const void *Type, uint32_t Dim,
131 uint32_t ElemType,
size_t Range[3]);
134 return getPropList().template has_property<propertyT>();
138 return getPropList().template get_property<propertyT>();
141 std::vector<ur_native_handle_t> getNativeVector(
backend BackendName)
const;
143 const std::unique_ptr<SYCLMemObjAllocator> &get_allocator_internal()
const;
147 void addOrReplaceAccessorProperties(
const property_list &PropertyList);
149 size_t getSize()
const;
151 void handleRelease()
const;
153 std::shared_ptr<detail::buffer_impl>
impl;
168 template <
typename T,
int dimensions = 1,
171 typename std::enable_if_t<(dimensions > 0) && (dimensions <= 3)>>
174 static_assert(is_device_copyable_v<T>,
175 "Underlying type of a buffer must be device copyable!");
185 template <
class Container>
187 std::void_t<std::enable_if_t<std::is_convertible_v<
189 decltype(std::declval<Container>().data())> (*)[],
191 decltype(std::declval<Container>().
size())>;
194 typename std::iterator_traits<It>::iterator_category,
195 std::input_iterator_tag>>;
196 template <
typename ItA,
typename ItB>
198 std::is_same_v<ItA, ItB> && !std::is_const_v<ItA>, ItA>;
208 CodeLoc, (
void *)
impl.get(),
nullptr, (
const void *)
typeid(T).name(),
216 bufferRange.
size() *
sizeof(T),
alignof(T), propList,
217 std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
221 CodeLoc, (
void *)
impl.get(),
nullptr, (
const void *)
typeid(T).name(),
234 CodeLoc, (
void *)
impl.get(), hostData, (
const void *)
typeid(T).name(),
242 hostData, bufferRange.
size() *
sizeof(T),
alignof(T), propList,
243 std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
247 CodeLoc, (
void *)
impl.get(), hostData, (
const void *)
typeid(T).name(),
251 template <
typename _T = T>
262 CodeLoc, (
void *)
impl.get(), hostData, (
const void *)
typeid(T).name(),
266 template <
typename _T = T>
272 hostData, bufferRange.
size() *
sizeof(T),
alignof(T), propList,
273 std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
277 CodeLoc, (
void *)
impl.get(), hostData, (
const void *)
typeid(T).name(),
281 buffer(
const std::shared_ptr<T> &hostData,
286 hostData, bufferRange.
size() *
sizeof(T),
alignof(T), propList,
287 std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
289 std::is_const<T>::value),
292 CodeLoc, (
void *)
impl.get(), (
void *)hostData.get(),
293 (
const void *)
typeid(T).name(),
dimensions,
sizeof(T),
297 buffer(
const std::shared_ptr<T[]> &hostData,
302 hostData, bufferRange.
size() *
sizeof(T),
alignof(T), propList,
303 std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
305 std::is_const<T>::value),
308 CodeLoc, (
void *)
impl.get(), (
void *)hostData.get(),
309 (
const void *)
typeid(T).name(),
dimensions,
sizeof(T),
313 buffer(
const std::shared_ptr<T> &hostData,
321 std::is_const<T>::value),
324 CodeLoc, (
void *)
impl.get(), (
void *)hostData.get(),
325 (
const void *)
typeid(T).name(),
dimensions,
sizeof(T),
329 buffer(
const std::shared_ptr<T[]> &hostData,
337 std::is_const<T>::value),
340 CodeLoc, (
void *)
impl.get(), (
void *)hostData.get(),
341 (
const void *)
typeid(T).name(),
dimensions,
sizeof(T),
345 template <
class InputIterator,
int N =
dimensions,
346 typename = EnableIfOneDimension<N>,
347 typename = EnableIfItInputIterator<InputIterator>>
348 buffer(InputIterator first, InputIterator last, AllocatorT allocator,
353 [first, last](
void *ToPtr) {
357 using IteratorValueType =
359 using IteratorNonConstValueType =
360 std::remove_const_t<IteratorValueType>;
361 using IteratorPointerToNonConstValueType =
362 std::add_pointer_t<IteratorNonConstValueType>;
364 static_cast<IteratorPointerToNonConstValueType
>(ToPtr));
366 std::distance(first, last) *
sizeof(T),
alignof(T), propList,
367 std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
369 detail::iterator_to_const_type_t<InputIterator>::value),
370 Range(
range<1>(std::distance(first, last))) {
371 size_t r[3] = {Range[0], 0, 0};
373 (
const void *)
typeid(T).name(),
377 template <
class InputIterator,
int N =
dimensions,
378 typename = EnableIfOneDimension<N>,
379 typename = EnableIfItInputIterator<InputIterator>>
380 buffer(InputIterator first, InputIterator last,
385 [first, last](
void *ToPtr) {
389 using IteratorValueType =
391 using IteratorNonConstValueType =
392 std::remove_const_t<IteratorValueType>;
393 using IteratorPointerToNonConstValueType =
394 std::add_pointer_t<IteratorNonConstValueType>;
396 static_cast<IteratorPointerToNonConstValueType
>(ToPtr));
398 std::distance(first, last) *
sizeof(T),
alignof(T), propList,
400 detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(),
401 detail::iterator_to_const_type_t<InputIterator>::value),
402 Range(
range<1>(std::distance(first, last))) {
403 size_t r[3] = {Range[0], 0, 0};
405 (
const void *)
typeid(T).name(),
410 template <
class Container,
int N =
dimensions,
411 typename = EnableIfOneDimension<N>,
412 typename = EnableIfContiguous<Container>>
413 buffer(Container &container, AllocatorT allocator,
417 container.data(), container.size() *
sizeof(T),
alignof(T),
419 std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
422 size_t r[3] = {Range[0], 0, 0};
424 CodeLoc, (
void *)
impl.get(), container.data(),
425 (
const void *)
typeid(T).name(),
dimensions,
sizeof(T), r);
429 template <
class Container,
int N =
dimensions,
430 typename = EnableIfOneDimension<N>,
431 typename = EnableIfContiguous<Container>>
434 :
buffer(container, {}, propList, CodeLoc) {}
440 OffsetInBytes(getOffsetInBytes<T>(baseIndex,
b.Range)),
443 CodeLoc, (
void *)
impl.get(),
impl.get(), (
const void *)
typeid(T).name(),
446 if (
b.is_sub_buffer())
448 "Cannot create sub buffer from sub buffer.");
451 "Requested sub-buffer size exceeds the size of the parent buffer");
452 if (!isContiguousRegion(baseIndex, subRange,
b.Range))
454 "Requested sub-buffer region is not contiguous");
460 OffsetInBytes(rhs.OffsetInBytes), IsSubBuffer(rhs.IsSubBuffer) {
462 CodeLoc, (
void *)
impl.get(),
impl.get(), (
const void *)
typeid(T).name(),
469 OffsetInBytes(rhs.OffsetInBytes), IsSubBuffer(rhs.IsSubBuffer) {
471 CodeLoc, (
void *)
impl.get(),
impl.get(), (
const void *)
typeid(T).name(),
481 buffer_plain::handleRelease();
482 }
catch (std::exception &e) {
498 size_t get_count()
const {
return size(); }
502 "get_size() is deprecated, please use byte_size() instead")
503 size_t get_size()
const {
return byte_size(); }
507 return buffer_plain::get_allocator_internal()
508 ->template getAllocator<AllocatorT>();
511 template <access::mode Mode, access::target Target = access::target::device>
519 *
this, CommandGroupHandler, {}, CodeLoc);
522 template <access::mode mode>
524 "use get_host_access instead")
529 accessor_property_list<>>
get_access(const detail::code_location
531 detail::code_location::
538 template <access::mode mode, access::target target = access::target::device>
547 "Requested accessor would exceed the bounds of the buffer");
551 *
this, commandGroupHandler, accessRange, accessOffset, {}, CodeLoc);
554 template <access::mode mode>
556 "use get_host_access instead")
569 "Requested accessor would exceed the bounds of the buffer");
574 *
this, accessRange, accessOffset, {}, CodeLoc);
577 template <
typename... Ts>
auto get_access(Ts... args) {
581 template <
typename... Ts>
583 return accessor{*
this, commandGroupHandler, args...};
590 template <
typename... Ts>
595 template <
typename Destination = std::
nullptr_t>
601 buffer_plain::set_final_data_internal();
604 template <
template <
typename WeakT>
class WeakPtrT,
typename WeakT>
605 std::enable_if_t<std::is_convertible_v<WeakPtrT<WeakT>, std::weak_ptr<WeakT>>>
607 std::weak_ptr<WeakT> TempFinalData(FinalData);
611 template <
typename WeakT>
613 buffer_plain::set_final_data_internal(
614 [FinalData](
const std::function<
void(
void *
const Ptr)> &F) {
615 if (std::shared_ptr<WeakT> LockedFinalData = FinalData.lock())
616 F(LockedFinalData.get());
620 template <
typename Destination>
624 buffer_plain::set_final_data_internal();
626 buffer_plain::set_final_data_internal(
627 [FinalData](
const std::function<
void(
void *
const Ptr)> &F) {
632 template <
typename Destination>
635 const size_t Size =
size();
636 buffer_plain::set_final_data_internal(
637 [FinalData, Size](
const std::function<
void(
void *
const Ptr)> &F) {
642 std::unique_ptr<DestinationValueT[]> ContiguousStorage(
643 new DestinationValueT[Size]);
644 F(ContiguousStorage.get());
645 std::copy(ContiguousStorage.get(), ContiguousStorage.get() + Size,
651 buffer_plain::set_final_data_internal();
658 template <
typename Re
interpretT,
int Re
interpretDim>
659 buffer<ReinterpretT, ReinterpretDim,
660 typename std::allocator_traits<AllocatorT>::template rebind_alloc<
661 std::remove_const_t<ReinterpretT>>>
663 if (
sizeof(ReinterpretT) * reinterpretRange.
size() !=
byte_size())
666 "Total size in bytes represented by the type and range of the "
667 "reinterpreted SYCL buffer does not equal the total size in bytes "
668 "represented by the type and range of this SYCL buffer");
670 return buffer<ReinterpretT, ReinterpretDim,
671 typename std::allocator_traits<AllocatorT>::
672 template rebind_alloc<std::remove_const_t<ReinterpretT>>>(
673 impl, reinterpretRange, OffsetInBytes, IsSubBuffer);
676 template <
typename Re
interpretT,
int Re
interpretDim = dimensions>
678 (
sizeof(ReinterpretT) ==
sizeof(T)) && (
dimensions == ReinterpretDim),
679 buffer<ReinterpretT, ReinterpretDim,
680 typename std::allocator_traits<AllocatorT>::template rebind_alloc<
681 std::remove_const_t<ReinterpretT>>>>
683 return buffer<ReinterpretT, ReinterpretDim,
684 typename std::allocator_traits<AllocatorT>::
685 template rebind_alloc<std::remove_const_t<ReinterpretT>>>(
689 template <
typename Re
interpretT,
int Re
interpretDim = dimensions>
690 std::enable_if_t<(ReinterpretDim == 1) &&
692 (
sizeof(ReinterpretT) !=
sizeof(T))),
696 if (sz %
sizeof(ReinterpretT) != 0)
698 "Total byte size of buffer is not evenly divisible "
699 "by the size of the reinterpreted type");
702 impl,
range<1>{sz /
sizeof(ReinterpretT)}, OffsetInBytes, IsSubBuffer);
706 return buffer_plain::template has_property<propertyT>();
709 template <
typename propertyT> propertyT
get_property()
const {
710 return buffer_plain::template get_property<propertyT>();
717 bool outOfBounds =
false;
719 outOfBounds |= newRange[i] + offset[i] > parentRange[i];
726 friend const decltype(Obj::impl) &
728 template <
typename A,
int dims,
typename C,
typename Enable>
733 template <
typename HT,
int HDims,
typename HAllocT>
745 size_t OffsetInBytes = 0;
746 bool IsSubBuffer =
false;
749 template <
int N = dimensions,
typename = EnableIfOneDimension<N>>
750 buffer(ur_native_handle_t MemObject,
const context &SyclContext,
751 bool OwnNativeHandle,
const event &AvailableEvent,
755 detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(),
756 OwnNativeHandle, AvailableEvent),
759 Range[0] = buffer_plain::getSize() /
sizeof(T);
761 CodeLoc, (
void *)
impl.get(), &MemObject, (
const void *)
typeid(T).name(),
765 void addOrReplaceAccessorProperties(
const property_list &PropertyList) {
766 buffer_plain::addOrReplaceAccessorProperties(PropertyList);
770 buffer_plain::deleteAccProps(Kind);
774 buffer(
const std::shared_ptr<detail::buffer_impl> &Impl,
775 range<dimensions> reinterpretRange,
size_t reinterpretOffset,
779 OffsetInBytes(reinterpretOffset), IsSubBuffer(isSubBuffer) {
781 CodeLoc, (
void *)
impl.get(), Impl.get(), (
const void *)
typeid(T).name(),
785 template <
typename Type,
int N>
786 size_t getOffsetInBytes(
const id<N> &offset,
const range<N> &range) {
790 bool isContiguousRegion(
const id<1> &,
const range<1> &,
const range<1> &) {
795 bool isContiguousRegion(
const id<2> &offset,
const range<2> &newRange,
796 const range<2> &parentRange) {
804 return newRange[0] == 1;
805 return newRange[1] == parentRange[1];
808 bool isContiguousRegion(
const id<3> &offset,
const range<3> &newRange,
809 const range<3> &parentRange) {
819 return newRange[0] == 1 && newRange[1] == 1;
821 return newRange[0] == 1 && newRange[2] == parentRange[2];
822 return newRange[1] == parentRange[1] && newRange[2] == parentRange[2];
832 template <backend BackendName>
835 auto NativeHandles = buffer_plain::getNativeVector(BackendName);
837 AllocatorT>::GetNativeObjs(NativeHandles);
841 #ifdef __cpp_deduction_guides
842 template <
class InputIterator,
class AllocatorT>
846 template <
class InputIterator>
847 buffer(InputIterator, InputIterator,
const property_list & = {})
849 template <
class Container,
class AllocatorT>
850 buffer(Container &, AllocatorT,
const property_list & = {})
851 -> buffer<typename Container::value_type, 1, AllocatorT>;
852 template <
class Container>
854 const property_list & = {}) -> buffer<typename Container::value_type, 1>;
855 template <
class T,
int dimensions,
class AllocatorT>
856 buffer(
const T *,
const range<dimensions> &, AllocatorT,
857 const property_list & = {}) -> buffer<T, dimensions, AllocatorT>;
858 template <
class T,
int dimensions>
859 buffer(
const T *,
const range<dimensions> &,
860 const property_list & = {}) -> buffer<T, dimensions>;
867 template <
typename T,
int dimensions,
typename AllocatorT>
868 struct hash<
sycl::buffer<T, dimensions, AllocatorT>> {
870 return hash<std::shared_ptr<sycl::detail::buffer_impl>>()(
Defines a shared array that can be used by kernels in queues.
bool has_property() const noexcept
buffer & operator=(const buffer &rhs)=default
AllocatorT get_allocator() const
__SYCL2020_DEPRECATED("get_size() is deprecated, please use byte_size() instead") size_t get_size() const
buffer(buffer &&rhs, const detail::code_location CodeLoc=detail::code_location::current())
buffer(InputIterator first, InputIterator last, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
__SYCL2020_DEPRECATED("get_access for host_accessor is deprecated, please " "use get_host_access instead") accessor< T
buffer(const buffer &rhs, const detail::code_location CodeLoc=detail::code_location::current())
buffer(InputIterator first, InputIterator last, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
buffer(EnableIfSameNonConstIterators< T, _T > const *hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
propertyT get_property() const
std::void_t< std::enable_if_t< std::is_convertible_v< std::remove_pointer_t< decltype(std::declval< Container >().data())>(*)[], const T(*)[]> >, decltype(std::declval< Container >().size())> EnableIfContiguous
buffer(T *hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
buffer(const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
size_t byte_size() const noexcept
buffer(Container &container, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
std::enable_if_t<(sizeof(ReinterpretT)==sizeof(T)) &&(dimensions==ReinterpretDim), buffer< ReinterpretT, ReinterpretDim, typename std::allocator_traits< AllocatorT >::template rebind_alloc< std::remove_const_t< ReinterpretT > > > > reinterpret() const
buffer(const std::shared_ptr< T[]> &hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
bool isOutOfBounds(const id< dimensions > &offset, const range< dimensions > &newRange, const range< dimensions > &parentRange)
bool operator!=(const buffer &rhs) const
buffer(buffer< T, dimensions, AllocatorT > &b, const id< dimensions > &baseIndex, const range< dimensions > &subRange, const detail::code_location CodeLoc=detail::code_location::current())
size_t size() const noexcept
void set_final_data(Destination finalData=nullptr)
std::enable_if_t< std::is_convertible_v< typename std::iterator_traits< It >::iterator_category, std::input_iterator_tag > > EnableIfItInputIterator
buffer(const std::shared_ptr< T > &hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
buffer(const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
bool operator==(const buffer &rhs) const
bool is_sub_buffer() const
const value_type & const_reference
range< dimensions > get_range() const
buffer(T *hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
buffer & operator=(buffer &&rhs)=default
buffer(Container &container, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
buffer(EnableIfSameNonConstIterators< T, _T > const *hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
buffer(const std::shared_ptr< T[]> &hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
auto get_host_access(Ts... args)
__SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead") size_t get_count() const
void set_write_back(bool flag=true)
typename std::enable_if_t< std::is_same_v< ItA, ItB > &&!std::is_const_v< ItA >, ItA > EnableIfSameNonConstIterators
buffer(const std::shared_ptr< T > &hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
accessor< T, dimensions, Mode, Target, access::placeholder::false_t, ext::oneapi::accessor_property_list<> > get_access(handler &CommandGroupHandler, const detail::code_location CodeLoc=detail::code_location::current())
typename std::enable_if_t< 1==dims > EnableIfOneDimension
AllocatorT allocator_type
The context class represents a SYCL context on which kernel functions may be executed.
buffer_plain(size_t SizeInBytes, size_t, const property_list &Props, std::unique_ptr< detail::SYCLMemObjAllocator > Allocator)
void set_final_data_internal()
bool has_property() const noexcept
std::shared_ptr< detail::buffer_impl > impl
buffer_plain(const std::shared_ptr< detail::buffer_impl > &impl)
buffer_plain(void *HostData, size_t SizeInBytes, size_t RequiredAlign, const property_list &Props, std::unique_ptr< detail::SYCLMemObjAllocator > Allocator)
propertyT get_property() const
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Command group handler class.
A unique identifier of an item in an index space.
Objects of the property_list class are containers for the SYCL properties.
Defines the iteration domain of either a single work-group in a parallel dispatch,...
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e)
std::enable_if_t< std::is_pointer_v< DataT > > EnableIfOutputPointerT
decltype(Obj::impl) const & getSyclObjImpl(const Obj &SyclObject)
size_t getLinearIndex(const T< Dims > &Index, const U< Dims > &Range)
typename std::iterator_traits< T >::value_type iterator_value_type_t
typename remove_pointer< T >::type remove_pointer_t
std::array< size_t, 3 > rangeToArray(const range< 3 > &r)
auto get_native_buffer(const buffer< DataT, Dimensions, Allocator, void > &Obj) -> backend_return_t< BackendName, buffer< DataT, Dimensions, Allocator, void >>
void constructorNotification(void *BufferObj, void *AccessorObj, access::target Target, access::mode Mode, const code_location &CodeLoc)
std::enable_if_t< !std::is_pointer_v< DataT > > EnableIfOutputIteratorT
buffer< T, Dimensions, AllocatorT, void > make_buffer_helper(ur_native_handle_t Handle, const context &Ctx, const event &Evt, bool OwnNativeHandle=true)
void copy(handler &CGH, const T *Src, T *Dest, size_t Count)
class __SYCL_EBO __SYCL_SPECIAL_CLASS Dimensions
detail::sycl_memory_object_allocator< DataT > buffer_allocator
typename backend_traits< Backend >::template return_type< SyclType > backend_return_t
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
_Abi const simd< _Tp, _Abi > & noexcept
size_t operator()(const sycl::buffer< T, dimensions, AllocatorT > &b) const
static constexpr code_location current(const char *fileName=__CODELOC_FILE_NAME, const char *funcName=__CODELOC_FUNCTION, unsigned long lineNo=__CODELOC_LINE, unsigned long columnNo=__CODELOC_COLUMN) noexcept