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
;
32 using ReverseIterator
=
33 typename ListContainer
<BaseElementType
>::ReverseIterator
;
34 using ConstReverseIterator
=
35 typename ListContainer
<BaseElementType
>::ConstReverseIterator
;
37 explicit SidecarListContainer(size_t max_size_for_derived_class
,
38 size_t max_size_for_sidecar
,
39 size_t num_of_elements_to_reserve_for
,
40 SidecarDestroyer destroyer
)
41 : list_(max_size_for_derived_class
+ max_size_for_sidecar
,
42 num_of_elements_to_reserve_for
),
43 destroyer_(destroyer
),
44 sidecar_offset_(max_size_for_derived_class
) {}
45 ~SidecarListContainer() { DestroyAllSidecars(); }
47 // Forward most of the reading logic to ListContainer.
48 bool empty() const { return list_
.empty(); }
49 size_t size() const { return list_
.size(); }
50 size_t GetCapacityInBytes() const { return list_
.GetCapacityInBytes(); }
51 ConstIterator
begin() const { return list_
.begin(); }
52 ConstIterator
end() const { return list_
.end(); }
54 template <typename DerivedElementType
>
55 DerivedElementType
* AllocateAndConstruct() {
56 return list_
.template AllocateAndConstruct
<DerivedElementType
>();
58 template <typename DerivedElementType
>
59 DerivedElementType
* AllocateAndCopyFrom(const DerivedElementType
* source
) {
60 return list_
.template AllocateAndCopyFrom
<DerivedElementType
>(source
);
69 destroyer_(GetSidecar(*list_
.rbegin()));
73 // This permits a client to exchange a pointer to an element to a pointer to
74 // its corresponding sidecar.
75 void* GetSidecar(BaseElementType
* element
) {
76 DCHECK_GT(sidecar_offset_
, 0u);
77 return reinterpret_cast<char*>(element
) + sidecar_offset_
;
79 const void* GetSidecar(const BaseElementType
* element
) {
80 DCHECK_GT(sidecar_offset_
, 0u);
81 return reinterpret_cast<const char*>(element
) + sidecar_offset_
;
85 void DestroyAllSidecars() {
86 for (auto* element
: list_
)
87 destroyer_(GetSidecar(element
));
90 ListContainer
<BaseElementType
> list_
;
91 SidecarDestroyer destroyer_
;
92 size_t sidecar_offset_
;
97 #endif // CC_BASE_SIDECAR_LIST_CONTAINER_H_