libstdc++
memory_resource
Go to the documentation of this file.
1 // <memory_resource> -*- C++ -*-
2 
3 // Copyright (C) 2018-2020 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file include/memory_resource
26  * This is a Standard C++ Library header.
27  */
28 
29 #ifndef _GLIBCXX_MEMORY_RESOURCE
30 #define _GLIBCXX_MEMORY_RESOURCE 1
31 
32 #pragma GCC system_header
33 
34 #if __cplusplus >= 201703L
35 
36 #include <memory> // align, allocator_arg_t, __uses_alloc
37 #include <utility> // pair, index_sequence
38 #include <vector> // vector
39 #include <cstddef> // size_t, max_align_t, byte
40 #include <shared_mutex> // shared_mutex
41 #include <bits/functexcept.h>
42 #include <bits/int_limits.h>
43 #include <debug/assertions.h>
44 
45 namespace std _GLIBCXX_VISIBILITY(default)
46 {
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48 namespace pmr
49 {
50 #ifdef _GLIBCXX_HAS_GTHREADS
51  // Header and all contents are present.
52 # define __cpp_lib_memory_resource 201603
53 #else
54  // The pmr::synchronized_pool_resource type is missing.
55 # define __cpp_lib_memory_resource 1
56 #endif
57 
58  class memory_resource;
59 
60 #if __cplusplus == 201703L
61  template<typename _Tp>
62  class polymorphic_allocator;
63 #else // C++20
64  template<typename _Tp = std::byte>
65  class polymorphic_allocator;
66 #endif
67 
68  // Global memory resources
69  memory_resource* new_delete_resource() noexcept;
70  memory_resource* null_memory_resource() noexcept;
71  memory_resource* set_default_resource(memory_resource* __r) noexcept;
72  memory_resource* get_default_resource() noexcept
73  __attribute__((__returns_nonnull__));
74 
75  // Pool resource classes
76  struct pool_options;
77 #ifdef _GLIBCXX_HAS_GTHREADS
78  class synchronized_pool_resource;
79 #endif
80  class unsynchronized_pool_resource;
81  class monotonic_buffer_resource;
82 
83  /// Class memory_resource
84  class memory_resource
85  {
86  static constexpr size_t _S_max_align = alignof(max_align_t);
87 
88  public:
89  memory_resource() = default;
90  memory_resource(const memory_resource&) = default;
91  virtual ~memory_resource(); // key function
92 
93  memory_resource& operator=(const memory_resource&) = default;
94 
95  [[nodiscard]]
96  void*
97  allocate(size_t __bytes, size_t __alignment = _S_max_align)
98  __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
99  { return do_allocate(__bytes, __alignment); }
100 
101  void
102  deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
103  __attribute__((__nonnull__))
104  { return do_deallocate(__p, __bytes, __alignment); }
105 
106  bool
107  is_equal(const memory_resource& __other) const noexcept
108  { return do_is_equal(__other); }
109 
110  private:
111  virtual void*
112  do_allocate(size_t __bytes, size_t __alignment) = 0;
113 
114  virtual void
115  do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
116 
117  virtual bool
118  do_is_equal(const memory_resource& __other) const noexcept = 0;
119  };
120 
121  inline bool
122  operator==(const memory_resource& __a, const memory_resource& __b) noexcept
123  { return &__a == &__b || __a.is_equal(__b); }
124 
125  inline bool
126  operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
127  { return !(__a == __b); }
128 
129 
130  // C++17 23.12.3 Class template polymorphic_allocator
131  template<typename _Tp>
132  class polymorphic_allocator
133  {
134  // _GLIBCXX_RESOLVE_LIB_DEFECTS
135  // 2975. Missing case for pair construction in polymorphic allocators
136  template<typename _Up>
137  struct __not_pair { using type = void; };
138 
139  template<typename _Up1, typename _Up2>
140  struct __not_pair<pair<_Up1, _Up2>> { };
141 
142  public:
143  using value_type = _Tp;
144 
145  polymorphic_allocator() noexcept
146  : _M_resource(get_default_resource())
147  { }
148 
149  polymorphic_allocator(memory_resource* __r) noexcept
150  __attribute__((__nonnull__))
151  : _M_resource(__r)
152  { _GLIBCXX_DEBUG_ASSERT(__r); }
153 
154  polymorphic_allocator(const polymorphic_allocator& __other) = default;
155 
156  template<typename _Up>
157  polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
158  : _M_resource(__x.resource())
159  { }
160 
161  polymorphic_allocator&
162  operator=(const polymorphic_allocator&) = delete;
163 
164  [[nodiscard]]
165  _Tp*
166  allocate(size_t __n)
167  __attribute__((__returns_nonnull__))
168  {
169  if (__n > (__detail::__int_limits<size_t>::max() / sizeof(_Tp)))
170  _GLIBCXX_THROW_OR_ABORT(bad_array_new_length());
171  return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
172  alignof(_Tp)));
173  }
174 
175  void
176  deallocate(_Tp* __p, size_t __n) noexcept
177  __attribute__((__nonnull__))
178  { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
179 
180 #if __cplusplus > 201703L
181  [[nodiscard]] void*
182  allocate_bytes(size_t __nbytes,
183  size_t __alignment = alignof(max_align_t))
184  { return _M_resource->allocate(__nbytes, __alignment); }
185 
186  void
187  deallocate_bytes(void* __p, size_t __nbytes,
188  size_t __alignment = alignof(max_align_t))
189  { _M_resource->deallocate(__p, __nbytes, __alignment); }
190 
191  template<typename _Up>
192  [[nodiscard]] _Up*
193  allocate_object(size_t __n = 1)
194  {
195  if ((__detail::__int_limits<size_t>::max() / sizeof(_Up)) < __n)
196  _GLIBCXX_THROW_OR_ABORT(bad_array_new_length());
197  return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
198  alignof(_Up)));
199  }
200 
201  template<typename _Up>
202  void
203  deallocate_object(_Up* __p, size_t __n = 1)
204  { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
205 
206  template<typename _Up, typename... _CtorArgs>
207  [[nodiscard]] _Up*
208  new_object(_CtorArgs&&... __ctor_args)
209  {
210  _Up* __p = allocate_object<_Up>();
211  __try
212  {
213  construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
214  }
215  __catch (...)
216  {
217  deallocate_object(__p);
218  __throw_exception_again;
219  }
220  return __p;
221  }
222 
223  template<typename _Up>
224  void
225  delete_object(_Up* __p)
226  {
227  destroy(__p);
228  deallocate_object(__p);
229  }
230 #endif // C++2a
231 
232 #if __cplusplus == 201703L
233  template<typename _Tp1, typename... _Args>
234  __attribute__((__nonnull__))
235  typename __not_pair<_Tp1>::type
236  construct(_Tp1* __p, _Args&&... __args)
237  {
238  // _GLIBCXX_RESOLVE_LIB_DEFECTS
239  // 2969. polymorphic_allocator::construct() shouldn't pass resource()
240  using __use_tag
241  = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
242  if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
243  ::new(__p) _Tp1(std::forward<_Args>(__args)...);
244  else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
245  ::new(__p) _Tp1(allocator_arg, *this,
246  std::forward<_Args>(__args)...);
247  else
248  ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
249  }
250 
251  template<typename _Tp1, typename _Tp2,
252  typename... _Args1, typename... _Args2>
253  __attribute__((__nonnull__))
254  void
255  construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
256  tuple<_Args1...> __x, tuple<_Args2...> __y)
257  {
258  auto __x_tag =
259  __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
260  auto __y_tag =
261  __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
262  index_sequence_for<_Args1...> __x_i;
263  index_sequence_for<_Args2...> __y_i;
264 
265  ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
266  _S_construct_p(__x_tag, __x_i, __x),
267  _S_construct_p(__y_tag, __y_i, __y));
268  }
269 
270  template<typename _Tp1, typename _Tp2>
271  __attribute__((__nonnull__))
272  void
273  construct(pair<_Tp1, _Tp2>* __p)
274  { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
275 
276  template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
277  __attribute__((__nonnull__))
278  void
279  construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
280  {
281  this->construct(__p, piecewise_construct,
282  forward_as_tuple(std::forward<_Up>(__x)),
283  forward_as_tuple(std::forward<_Vp>(__y)));
284  }
285 
286  template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
287  __attribute__((__nonnull__))
288  void
289  construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
290  {
291  this->construct(__p, piecewise_construct,
292  forward_as_tuple(__pr.first),
293  forward_as_tuple(__pr.second));
294  }
295 
296  template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
297  __attribute__((__nonnull__))
298  void
299  construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
300  {
301  this->construct(__p, piecewise_construct,
302  forward_as_tuple(std::forward<_Up>(__pr.first)),
303  forward_as_tuple(std::forward<_Vp>(__pr.second)));
304  }
305 #else
306  template<typename _Tp1, typename... _Args>
307  __attribute__((__nonnull__))
308  void
309  construct(_Tp1* __p, _Args&&... __args)
310  {
311  std::uninitialized_construct_using_allocator(__p, *this,
312  std::forward<_Args>(__args)...);
313  }
314 #endif
315 
316  template<typename _Up>
317  __attribute__((__nonnull__))
318  void
319  destroy(_Up* __p)
320  { __p->~_Up(); }
321 
322  polymorphic_allocator
323  select_on_container_copy_construction() const noexcept
324  { return polymorphic_allocator(); }
325 
326  memory_resource*
327  resource() const noexcept
328  __attribute__((__returns_nonnull__))
329  { return _M_resource; }
330 
331  private:
332  using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
333  using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
334 
335  template<typename _Ind, typename... _Args>
336  static tuple<_Args&&...>
337  _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
338  { return std::move(__t); }
339 
340  template<size_t... _Ind, typename... _Args>
341  static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
342  _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
343  tuple<_Args...>& __t)
344  {
345  return {
346  allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
347  };
348  }
349 
350  template<size_t... _Ind, typename... _Args>
351  static tuple<_Args&&..., polymorphic_allocator>
352  _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
353  tuple<_Args...>& __t)
354  { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
355 
356  memory_resource* _M_resource;
357  };
358 
359  template<typename _Tp1, typename _Tp2>
360  inline bool
361  operator==(const polymorphic_allocator<_Tp1>& __a,
362  const polymorphic_allocator<_Tp2>& __b) noexcept
363  { return *__a.resource() == *__b.resource(); }
364 
365  template<typename _Tp1, typename _Tp2>
366  inline bool
367  operator!=(const polymorphic_allocator<_Tp1>& __a,
368  const polymorphic_allocator<_Tp2>& __b) noexcept
369  { return !(__a == __b); }
370 
371 
372  /// Parameters for tuning a pool resource's behaviour.
373  struct pool_options
374  {
375  /** @brief Upper limit on number of blocks in a chunk.
376  *
377  * A lower value prevents allocating huge chunks that could remain mostly
378  * unused, but means pools will need to replenished more frequently.
379  */
380  size_t max_blocks_per_chunk = 0;
381 
382  /* @brief Largest block size (in bytes) that should be served from pools.
383  *
384  * Larger allocations will be served directly by the upstream resource,
385  * not from one of the pools managed by the pool resource.
386  */
387  size_t largest_required_pool_block = 0;
388  };
389 
390  // Common implementation details for un-/synchronized pool resources.
391  class __pool_resource
392  {
393  friend class synchronized_pool_resource;
394  friend class unsynchronized_pool_resource;
395 
396  __pool_resource(const pool_options& __opts, memory_resource* __upstream);
397 
398  ~__pool_resource();
399 
400  __pool_resource(const __pool_resource&) = delete;
401  __pool_resource& operator=(const __pool_resource&) = delete;
402 
403  // Allocate a large unpooled block.
404  void*
405  allocate(size_t __bytes, size_t __alignment);
406 
407  // Deallocate a large unpooled block.
408  void
409  deallocate(void* __p, size_t __bytes, size_t __alignment);
410 
411 
412  // Deallocate unpooled memory.
413  void release() noexcept;
414 
415  memory_resource* resource() const noexcept
416  { return _M_unpooled.get_allocator().resource(); }
417 
418  struct _Pool;
419 
420  _Pool* _M_alloc_pools();
421 
422  const pool_options _M_opts;
423 
424  struct _BigBlock;
425  // Collection of blocks too big for any pool, sorted by address.
426  // This also stores the only copy of the upstream memory resource pointer.
427  _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled;
428 
429  const int _M_npools;
430  };
431 
432 #ifdef _GLIBCXX_HAS_GTHREADS
433  /// A thread-safe memory resource that manages pools of fixed-size blocks.
434  class synchronized_pool_resource : public memory_resource
435  {
436  public:
437  synchronized_pool_resource(const pool_options& __opts,
438  memory_resource* __upstream)
439  __attribute__((__nonnull__));
440 
441  synchronized_pool_resource()
442  : synchronized_pool_resource(pool_options(), get_default_resource())
443  { }
444 
445  explicit
446  synchronized_pool_resource(memory_resource* __upstream)
447  __attribute__((__nonnull__))
448  : synchronized_pool_resource(pool_options(), __upstream)
449  { }
450 
451  explicit
452  synchronized_pool_resource(const pool_options& __opts)
453  : synchronized_pool_resource(__opts, get_default_resource()) { }
454 
455  synchronized_pool_resource(const synchronized_pool_resource&) = delete;
456 
457  virtual ~synchronized_pool_resource();
458 
459  synchronized_pool_resource&
460  operator=(const synchronized_pool_resource&) = delete;
461 
462  void release();
463 
464  memory_resource*
465  upstream_resource() const noexcept
466  __attribute__((__returns_nonnull__))
467  { return _M_impl.resource(); }
468 
469  pool_options options() const noexcept { return _M_impl._M_opts; }
470 
471  protected:
472  void*
473  do_allocate(size_t __bytes, size_t __alignment) override;
474 
475  void
476  do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
477 
478  bool
479  do_is_equal(const memory_resource& __other) const noexcept override
480  { return this == &__other; }
481 
482  public:
483  // Thread-specific pools (only public for access by implementation details)
484  struct _TPools;
485 
486  private:
487  _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&);
488  _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&);
489  auto _M_thread_specific_pools() noexcept;
490 
491  __pool_resource _M_impl;
492  __gthread_key_t _M_key;
493  // Linked list of thread-specific pools. All threads share _M_tpools[0].
494  _TPools* _M_tpools = nullptr;
495  mutable shared_mutex _M_mx;
496  };
497 #endif
498 
499  /// A non-thread-safe memory resource that manages pools of fixed-size blocks.
500  class unsynchronized_pool_resource : public memory_resource
501  {
502  public:
503  [[__gnu__::__nonnull__]]
504  unsynchronized_pool_resource(const pool_options& __opts,
505  memory_resource* __upstream);
506 
507  unsynchronized_pool_resource()
508  : unsynchronized_pool_resource(pool_options(), get_default_resource())
509  { }
510 
511  [[__gnu__::__nonnull__]]
512  explicit
513  unsynchronized_pool_resource(memory_resource* __upstream)
514  : unsynchronized_pool_resource(pool_options(), __upstream)
515  { }
516 
517  explicit
518  unsynchronized_pool_resource(const pool_options& __opts)
519  : unsynchronized_pool_resource(__opts, get_default_resource()) { }
520 
521  unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
522 
523  virtual ~unsynchronized_pool_resource();
524 
525  unsynchronized_pool_resource&
526  operator=(const unsynchronized_pool_resource&) = delete;
527 
528  void release();
529 
530  [[__gnu__::__returns_nonnull__]]
531  memory_resource*
532  upstream_resource() const noexcept
533  { return _M_impl.resource(); }
534 
535  pool_options options() const noexcept { return _M_impl._M_opts; }
536 
537  protected:
538  void*
539  do_allocate(size_t __bytes, size_t __alignment) override;
540 
541  void
542  do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
543 
544  bool
545  do_is_equal(const memory_resource& __other) const noexcept override
546  { return this == &__other; }
547 
548  private:
549  using _Pool = __pool_resource::_Pool;
550 
551  auto _M_find_pool(size_t) noexcept;
552 
553  __pool_resource _M_impl;
554  _Pool* _M_pools = nullptr;
555  };
556 
557  class monotonic_buffer_resource : public memory_resource
558  {
559  public:
560  explicit
561  monotonic_buffer_resource(memory_resource* __upstream) noexcept
562  __attribute__((__nonnull__))
563  : _M_upstream(__upstream)
564  { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); }
565 
566  monotonic_buffer_resource(size_t __initial_size,
567  memory_resource* __upstream) noexcept
568  __attribute__((__nonnull__))
569  : _M_next_bufsiz(__initial_size),
570  _M_upstream(__upstream)
571  {
572  _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
573  _GLIBCXX_DEBUG_ASSERT(__initial_size > 0);
574  }
575 
576  monotonic_buffer_resource(void* __buffer, size_t __buffer_size,
577  memory_resource* __upstream) noexcept
578  __attribute__((__nonnull__(4)))
579  : _M_current_buf(__buffer), _M_avail(__buffer_size),
580  _M_next_bufsiz(_S_next_bufsize(__buffer_size)),
581  _M_upstream(__upstream),
582  _M_orig_buf(__buffer), _M_orig_size(__buffer_size)
583  {
584  _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
585  _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0);
586  }
587 
588  monotonic_buffer_resource() noexcept
589  : monotonic_buffer_resource(get_default_resource())
590  { }
591 
592  explicit
593  monotonic_buffer_resource(size_t __initial_size) noexcept
594  : monotonic_buffer_resource(__initial_size, get_default_resource())
595  { }
596 
597  monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept
598  : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource())
599  { }
600 
601  monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
602 
603  virtual ~monotonic_buffer_resource(); // key function
604 
605  monotonic_buffer_resource&
606  operator=(const monotonic_buffer_resource&) = delete;
607 
608  void
609  release() noexcept
610  {
611  if (_M_head)
612  _M_release_buffers();
613 
614  // reset to initial state at contruction:
615  if ((_M_current_buf = _M_orig_buf))
616  {
617  _M_avail = _M_orig_size;
618  _M_next_bufsiz = _S_next_bufsize(_M_orig_size);
619  }
620  else
621  {
622  _M_avail = 0;
623  _M_next_bufsiz = _M_orig_size;
624  }
625  }
626 
627  memory_resource*
628  upstream_resource() const noexcept
629  __attribute__((__returns_nonnull__))
630  { return _M_upstream; }
631 
632  protected:
633  void*
634  do_allocate(size_t __bytes, size_t __alignment) override
635  {
636  if (__bytes == 0)
637  __bytes = 1; // Ensures we don't return the same pointer twice.
638 
639  void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
640  if (!__p)
641  {
642  _M_new_buffer(__bytes, __alignment);
643  __p = _M_current_buf;
644  }
645  _M_current_buf = (char*)_M_current_buf + __bytes;
646  _M_avail -= __bytes;
647  return __p;
648  }
649 
650  void
651  do_deallocate(void*, size_t, size_t) override
652  { }
653 
654  bool
655  do_is_equal(const memory_resource& __other) const noexcept override
656  { return this == &__other; }
657 
658  private:
659  // Update _M_current_buf and _M_avail to refer to a new buffer with
660  // at least the specified size and alignment, allocated from upstream.
661  void
662  _M_new_buffer(size_t __bytes, size_t __alignment);
663 
664  // Deallocate all buffers obtained from upstream.
665  void
666  _M_release_buffers() noexcept;
667 
668  static size_t
669  _S_next_bufsize(size_t __buffer_size) noexcept
670  {
671  if (__buffer_size == 0)
672  __buffer_size = 1;
673  return __buffer_size * _S_growth_factor;
674  }
675 
676  static constexpr size_t _S_init_bufsize = 128 * sizeof(void*);
677  static constexpr float _S_growth_factor = 1.5;
678 
679  void* _M_current_buf = nullptr;
680  size_t _M_avail = 0;
681  size_t _M_next_bufsiz = _S_init_bufsize;
682 
683  // Initial values set at construction and reused by release():
684  memory_resource* const _M_upstream;
685  void* const _M_orig_buf = nullptr;
686  size_t const _M_orig_size = _M_next_bufsiz;
687 
688  class _Chunk;
689  _Chunk* _M_head = nullptr;
690  };
691 
692 } // namespace pmr
693 _GLIBCXX_END_NAMESPACE_VERSION
694 } // namespace std
695 
696 #endif // C++17
697 #endif // _GLIBCXX_MEMORY_RESOURCE