1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
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 #ifndef sw_Memset_hpp
16 #define sw_Memset_hpp
17 
18 #include <cstring>
19 #include <type_traits>
20 
21 // GCC 8+ warns that
22 // "‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘T’;
23 //  use assignment or value-initialization instead [-Werror=class-memaccess]"
24 // This is benign iff it happens before any of the base or member constructors are called.
25 #if defined(__GNUC__) && (__GNUC__ >= 8)
26 #	pragma GCC diagnostic push
27 #	pragma GCC diagnostic ignored "-Wclass-memaccess"
28 #endif
29 
30 namespace sw {
31 
32 // Memset<> is a helper class for clearing the memory of objects at construction.
33 // It is useful as the *first* base class of map keys which may contain padding
34 // bytes or bits otherwise left uninitialized.
35 template<class T>
36 struct Memset
37 {
Memsetsw::Memset38 	Memset(T *object, int val)
39 	{
40 		static_assert(std::is_base_of<Memset<T>, T>::value, "Memset<T> must only clear the memory of a type of which it is a base class");
41 		static_assert(!std::is_polymorphic<T>::value, "Memset<T> must not be used with classes that have virtual functions");
42 		::memset(object, 0, sizeof(T));
43 	}
44 
45 	// Don't rely on the implicitly declared copy constructor and copy assignment operator.
46 	// They can leave padding bytes uninitialized.
Memsetsw::Memset47 	Memset(const Memset &rhs)
48 	{
49 		::memcpy(this, &rhs, sizeof(T));
50 	}
51 
operator =sw::Memset52 	Memset &operator=(const Memset &rhs)
53 	{
54 		::memcpy(this, &rhs, sizeof(T));
55 		return *this;
56 	}
57 
58 	// The compiler won't declare an implicit move constructor and move assignment operator
59 	// due to having a user-defined copy constructor and copy assignment operator. Delete
60 	// them for explicitness. We always want memcpy() being called.
61 	Memset(const Memset &&rhs) = delete;
62 	Memset &operator=(const Memset &&rhs) = delete;
63 
operator ==(const T & a,const T & b)64 	friend bool operator==(const T &a, const T &b)
65 	{
66 		return ::memcmp(&a, &b, sizeof(T)) == 0;
67 	}
68 
operator !=(const T & a,const T & b)69 	friend bool operator!=(const T &a, const T &b)
70 	{
71 		return ::memcmp(&a, &b, sizeof(T)) != 0;
72 	}
73 
operator <(const T & a,const T & b)74 	friend bool operator<(const T &a, const T &b)
75 	{
76 		return ::memcmp(&a, &b, sizeof(T)) < 0;
77 	}
78 };
79 
80 }  // namespace sw
81 
82 // Restore -Wclass-memaccess
83 #if defined(__GNUC__) && (__GNUC__ >= 8)
84 #	pragma GCC diagnostic pop
85 #endif
86 
87 #endif  // sw_Memset_hpp