1 /** @file
2 
3   Extendible
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22 
23   @section details Details
24 
25 ////////////////////////////////////////////
26   Implements:
27   * Extendible<Derived_t>
28   * Schema
29   * fieldAdd
30   * fieldFind
31  */
32 
33 #include "tscore/Extendible.h"
34 
35 namespace ext
36 {
37 namespace details
38 {
39   ////////////////////////////////////////////////////
40   // Schema Methods
41 
~Schema()42   Schema::~Schema() {}
43 
44   void
updateMemOffsets()45   Schema::updateMemOffsets()
46   {
47     ink_release_assert(cnt_constructed == cnt_destructed);
48 
49     uint32_t acc_offset = 0;
50     alloc_align         = 1;
51 
52     for (auto &pair_fld : fields) {
53       alloc_align = std::max(alloc_align, pair_fld.second.align);
54     }
55 
56     // allocate fields from largest to smallest alignment
57     uint8_t processing_align = alloc_align;
58     while (processing_align > 0) {
59       uint8_t next_align = 0;
60       for (auto &pair_fld : fields) {
61         auto &fld = pair_fld.second;
62         if (fld.align == processing_align) {
63           fld.field_offset = acc_offset;
64           acc_offset += fld.size;
65         } else if (fld.align < processing_align) {
66           next_align = std::max(next_align, fld.align);
67         }
68       }
69       processing_align = next_align;
70     }
71 
72     // align '0' are packed bit allocations.
73     uint32_t acc_bit_offset = 0;
74     for (auto &pair_fld : fields) {
75       auto &fld = pair_fld.second;
76       if (fld.align == 0) {
77         fld.field_offset = acc_offset + acc_bit_offset / 8;
78         fld.mask         = 1 << (acc_bit_offset % 8);
79         ++acc_bit_offset;
80       }
81     }
82 
83     alloc_size = acc_offset + (acc_bit_offset + 7) / 8;
84   }
85 
86   bool
reset()87   Schema::reset()
88   {
89     if (cnt_constructed > cnt_destructed) {
90       // free instances before calling this so we don't leak memory
91       return false;
92     }
93     fields.clear();
94     updateMemOffsets();
95     return true;
96   }
97 
98   void
callConstructor(uintptr_t ext_loc)99   Schema::callConstructor(uintptr_t ext_loc)
100   {
101     ink_assert(ext_loc);
102     ++cnt_fld_constructed; // don't allow schema modification
103     ink_assert(cnt_fld_constructed <= cnt_constructed);
104 
105     // init all extendible memory to 0, in case constructors don't
106     memset(reinterpret_cast<void *>(ext_loc), 0, alloc_size);
107 
108     for (auto const &elm : fields) {
109       if (elm.second.constructor) {
110         elm.second.constructor(FieldPtr(ext_loc + elm.second.field_offset));
111       }
112     }
113   }
114 
115   void
callDestructor(uintptr_t ext_loc)116   Schema::callDestructor(uintptr_t ext_loc)
117   {
118     ink_assert(ext_loc);
119     for (auto const &elm : fields) {
120       if (elm.second.destructor) {
121         elm.second.destructor(FieldPtr(ext_loc + elm.second.field_offset));
122       }
123     }
124   }
125 
126   size_t
fullSize(const size_t base_size) const127   Schema::fullSize(const size_t base_size) const
128   {
129     ink_assert(base_size);
130     return ROUNDUP(base_size, alloc_align) + alloc_size;
131   }
132 
133   bool
no_instances() const134   Schema::no_instances() const
135   {
136     return cnt_constructed == cnt_destructed;
137   }
138 } // namespace details
139 
140 } // namespace ext
141