1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CC_BASE_SIDECAR_LIST_CONTAINER_H_
6 #define CC_BASE_SIDECAR_LIST_CONTAINER_H_
8 #include "base/logging.h"
9 #include "cc/base/list_container.h"
13 // This is a container, based on ListContainer, which allocates space in a
14 // contiguous block for objects subclassing BaseElementType, as well as an
15 // additional "sidecar" of opaque type.
17 // It takes a pointer to a function for tearing down sidecar objects, which must
18 // free any resources held by it as its memory will be deallocated by the
19 // container afterwards. When an element is constructed, callers are expected to
20 // immediately construct the sidecar as well (such that the sidecar destroyer
21 // will run safely and successfully).
23 // TODO(jbroman): It would be nice to be clear about the memory alignment
24 // constraints here, but that probably requires closer inspection of
25 // ListContainer first.
26 template <class BaseElementType
>
27 class SidecarListContainer
{
29 using SidecarDestroyer
= void (*)(void* sidecar
);
30 using Iterator
= typename ListContainer
<BaseElementType
>::Iterator
;
31 using ConstIterator
= typename ListContainer
<BaseElementType
>::ConstIterator
;
33 explicit SidecarListContainer(size_t max_size_for_derived_class
,
34 size_t max_size_for_sidecar
,
35 size_t num_of_elements_to_reserve_for
,
36 SidecarDestroyer destroyer
)
37 : list_(max_size_for_derived_class
+ max_size_for_sidecar
,
38 num_of_elements_to_reserve_for
),
39 destroyer_(destroyer
),
40 sidecar_offset_(max_size_for_derived_class
) {}
41 ~SidecarListContainer() { DestroyAllSidecars(); }
43 // Forward most of the reading logic to ListContainer.
44 bool empty() const { return list_
.empty(); }
45 size_t size() const { return list_
.size(); }
46 ConstIterator
begin() const { return list_
.begin(); }
47 ConstIterator
end() const { return list_
.end(); }
49 template <typename DerivedElementType
>
50 DerivedElementType
* AllocateAndConstruct() {
51 return list_
.template AllocateAndConstruct
<DerivedElementType
>();
53 template <typename DerivedElementType
>
54 DerivedElementType
* AllocateAndCopyFrom(const DerivedElementType
* source
) {
55 return list_
.template AllocateAndCopyFrom
<DerivedElementType
>(source
);
63 // This permits a client to exchange a pointer to an element to a pointer to
64 // its corresponding sidecar.
65 void* GetSidecar(BaseElementType
* element
) {
66 DCHECK_GT(sidecar_offset_
, 0u);
67 return reinterpret_cast<char*>(element
) + sidecar_offset_
;
69 const void* GetSidecar(const BaseElementType
* element
) {
70 DCHECK_GT(sidecar_offset_
, 0u);
71 return reinterpret_cast<const char*>(element
) + sidecar_offset_
;
75 void DestroyAllSidecars() {
76 for (auto* element
: list_
)
77 destroyer_(GetSidecar(element
));
80 ListContainer
<BaseElementType
> list_
;
81 SidecarDestroyer destroyer_
;
82 size_t sidecar_offset_
;
87 #endif // CC_BASE_SIDECAR_LIST_CONTAINER_H_