summaryrefslogtreecommitdiffstats
path: root/cc/base/sidecar_list_container.h
blob: 5135ab1d7d2a8a78d48b5a85ed230abacda6cf6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_BASE_SIDECAR_LIST_CONTAINER_H_
#define CC_BASE_SIDECAR_LIST_CONTAINER_H_

#include "base/logging.h"
#include "cc/base/list_container.h"

namespace cc {

// This is a container, based on ListContainer, which allocates space in a
// contiguous block for objects subclassing BaseElementType, as well as an
// additional "sidecar" of opaque type.
//
// It takes a pointer to a function for tearing down sidecar objects, which must
// free any resources held by it as its memory will be deallocated by the
// container afterwards. When an element is constructed, callers are expected to
// immediately construct the sidecar as well (such that the sidecar destroyer
// will run safely and successfully).
//
// TODO(jbroman): It would be nice to be clear about the memory alignment
// constraints here, but that probably requires closer inspection of
// ListContainer first.
template <class BaseElementType>
class SidecarListContainer {
 public:
  using SidecarDestroyer = void (*)(void* sidecar);
  using Iterator = typename ListContainer<BaseElementType>::Iterator;
  using ConstIterator = typename ListContainer<BaseElementType>::ConstIterator;
  using ReverseIterator =
      typename ListContainer<BaseElementType>::ReverseIterator;
  using ConstReverseIterator =
      typename ListContainer<BaseElementType>::ConstReverseIterator;

  explicit SidecarListContainer(size_t max_size_for_derived_class,
                                size_t max_size_for_sidecar,
                                size_t num_of_elements_to_reserve_for,
                                SidecarDestroyer destroyer)
      : list_(max_size_for_derived_class + max_size_for_sidecar,
              num_of_elements_to_reserve_for),
        destroyer_(destroyer),
        sidecar_offset_(max_size_for_derived_class) {}
  ~SidecarListContainer() { DestroyAllSidecars(); }

  // Forward most of the reading logic to ListContainer.
  bool empty() const { return list_.empty(); }
  size_t size() const { return list_.size(); }
  size_t GetCapacityInBytes() const { return list_.GetCapacityInBytes(); }
  ConstIterator begin() const { return list_.begin(); }
  ConstIterator end() const { return list_.end(); }

  template <typename DerivedElementType>
  DerivedElementType* AllocateAndConstruct() {
    return list_.template AllocateAndConstruct<DerivedElementType>();
  }
  template <typename DerivedElementType>
  DerivedElementType* AllocateAndCopyFrom(const DerivedElementType* source) {
    return list_.template AllocateAndCopyFrom<DerivedElementType>(source);
  }

  void clear() {
    DestroyAllSidecars();
    list_.clear();
  }

  void RemoveLast() {
    destroyer_(GetSidecar(*list_.rbegin()));
    list_.RemoveLast();
  }

  // This permits a client to exchange a pointer to an element to a pointer to
  // its corresponding sidecar.
  void* GetSidecar(BaseElementType* element) {
    DCHECK_GT(sidecar_offset_, 0u);
    return reinterpret_cast<char*>(element) + sidecar_offset_;
  }
  const void* GetSidecar(const BaseElementType* element) {
    DCHECK_GT(sidecar_offset_, 0u);
    return reinterpret_cast<const char*>(element) + sidecar_offset_;
  }

 private:
  void DestroyAllSidecars() {
    for (auto* element : list_)
      destroyer_(GetSidecar(element));
  }

  ListContainer<BaseElementType> list_;
  SidecarDestroyer destroyer_;
  size_t sidecar_offset_;
};

}  // namespace cc

#endif  // CC_BASE_SIDECAR_LIST_CONTAINER_H_