1 /*
2  * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef CORE__ECS_HELPER__PROPERTY_TOOLS__PROPERTY_VALUE_H
17 #define CORE__ECS_HELPER__PROPERTY_TOOLS__PROPERTY_VALUE_H
18 
19 #include <cassert>
20 #include <cstddef>
21 #include <cstdint>
22 
23 #include <base/containers/array_view.h>
24 #include <base/containers/iterator.h>
25 #include <base/containers/string_view.h>
26 #include <base/namespace.h>
27 #include <core/namespace.h>
28 #include <core/property/property.h>
29 #include <base/util/log.h>
30 #include <base/containers/type_traits.h>
31 #include <core/property/property_types.h>
32 
CORE_BEGIN_NAMESPACE()33 CORE_BEGIN_NAMESPACE()
34 class PropertyValue {
35 public:
36     PropertyValue() noexcept : count_(0), data_(nullptr), index_(0) {}
37     ~PropertyValue() = default;
38     PropertyValue(const PropertyValue& other) noexcept = default;
39 
40     PropertyValue(PropertyValue&& other) noexcept
41         : type_(other.type_), // exchange(other.type_, PropertyType::INVALID)),
42           count_(BASE_NS::exchange(other.count_, 0U)), data_(BASE_NS::exchange(other.data_, nullptr)),
43           index_(BASE_NS::exchange(other.index_, 0U))
44     {}
45     explicit constexpr PropertyValue(const Property* type, void* rawData, size_t cnt) noexcept
46         : type_(type), count_(cnt), data_(rawData), index_(0U)
47     {}
48 
49     constexpr size_t Size() const
50     {
51         return count_;
52     }
53     constexpr PropertyTypeDecl GetType() const
54     {
55         return type_->type;
56     }
57     constexpr operator PropertyTypeDecl() const
58     {
59         return type_->type;
60     }
61     constexpr bool operator==(const PropertyTypeDecl& other) const
62     {
63         return type_->type.compareHash == other.compareHash;
64     }
65 
66     BASE_NS::array_view<const Property> MetaData() const
67     {
68         if (type_) {
69             return type_->metaData.memberProperties;
70         }
71         return {};
72     }
73     const Property* MetaData(size_t index) const
74     {
75         if (type_) {
76             const auto& meta = type_->metaData.memberProperties;
77             if (index < meta.size()) {
78                 return &meta[index];
79             }
80         }
81         return nullptr;
82     }
83 
84     // void* access
85     explicit constexpr operator void*()
86     {
87         return data_;
88     }
89     explicit constexpr operator void const*() const
90     {
91         return data_;
92     }
93 
94     // safe
95     PropertyValue operator[](const size_t index) const
96     {
97         BASE_ASSERT(type_->type.isArray); // This accessor type is valid only for arrays.
98         BASE_ASSERT(index < type_->count);
99         return PropertyValue(type_, data_, 1, index);
100     }
101     PropertyValue operator[](const size_t index)
102     {
103         BASE_ASSERT(type_->type.isArray); // This accessor type is valid only for arrays.
104         BASE_ASSERT(index < type_->count);
105         return PropertyValue(type_, data_, 1, index);
106     }
107 
108     PropertyValue operator[](BASE_NS::string_view name) const
109     {
110         uintptr_t offset = reinterpret_cast<uintptr_t>(data_);
111         const auto nameHash = BASE_NS::FNV1aHash(name.data(), name.size());
112         for (const auto& p : type_->metaData.memberProperties) {
113             if ((nameHash == p.hash) && (p.name == name)) {
114                 return PropertyValue(&p, reinterpret_cast<void*>(offset + p.offset), p.count);
115             }
116         }
117         // no such member property
118         return {};
119     }
120 
121     // unsafe
122     template<typename T>
123     [[deprecated]] constexpr operator T() const
124     {
125         return reinterpret_cast<T*>(data_)[index_];
126     }
127 
128     template<typename T>
129     [[deprecated]] constexpr operator T&()
130     {
131         return reinterpret_cast<T*>(data_)[index_];
132     }
133 
134     template<typename T>
135     [[deprecated]] PropertyValue& operator=(T v)
136     {
137         reinterpret_cast<T*>(data_)[index_] = v;
138         return *this;
139     }
140 
141     PropertyValue& operator=(const PropertyValue& other) noexcept = default;
142 
143     PropertyValue& operator=(PropertyValue&& other) noexcept
144     {
145         if (this != &other) {
146             type_ = BASE_NS::exchange(other.type_, {});
147             count_ = BASE_NS::exchange(other.count_, 0U);
148             data_ = BASE_NS::exchange(other.data_, nullptr);
149             index_ = BASE_NS::exchange(other.index_, 0U);
150         }
151         return *this;
152     }
153 
154 private:
155     const Property* type_ { nullptr };
156     size_t count_;
157     void* data_;
158     size_t index_;
159     explicit constexpr PropertyValue(const Property* type, void* rawData, size_t cnt, size_t index)
160         : type_(type), count_(cnt), data_(rawData), index_(index)
161     {}
162 };
163 CORE_END_NAMESPACE()
164 
165 #endif // CORE__ECS_HELPER__PROPERTY_TOOLS__PROPERTY_VALUE_H
166