summaryrefslogtreecommitdiff
path: root/absl/synchronization/mutex_method_pointer_test.cc
blob: 1ec801a001fe07818bad96db1defc18c7d1beebc (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "absl/synchronization/mutex.h"

#include <cstdlib>
#include <string>

#include "gtest/gtest.h"
#include "absl/base/config.h"

namespace {

class IncompleteClass;

#ifdef _MSC_VER
// These tests verify expectations about sizes of MSVC pointers to methods.
// Pointers to methods are distinguished by whether their class hierachies
// contain single inheritance, multiple inheritance, or virtual inheritence.

// Declare classes of the various MSVC inheritance types.
class __single_inheritance SingleInheritance{};
class __multiple_inheritance MultipleInheritance;
class __virtual_inheritance VirtualInheritance;

TEST(MutexMethodPointerTest, MicrosoftMethodPointerSize) {
  void (SingleInheritance::*single_inheritance_method_pointer)();
  void (MultipleInheritance::*multiple_inheritance_method_pointer)();
  void (VirtualInheritance::*virtual_inheritance_method_pointer)();

#if defined(_M_IX86) || defined(_M_ARM)
  static_assert(sizeof(single_inheritance_method_pointer) == 4,
                "Unexpected sizeof(single_inheritance_method_pointer).");
  static_assert(sizeof(multiple_inheritance_method_pointer) == 8,
                "Unexpected sizeof(multiple_inheritance_method_pointer).");
  static_assert(sizeof(virtual_inheritance_method_pointer) == 12,
                "Unexpected sizeof(virtual_inheritance_method_pointer).");
#elif defined(_M_X64) || defined(__aarch64__)
  static_assert(sizeof(single_inheritance_method_pointer) == 8,
                "Unexpected sizeof(single_inheritance_method_pointer).");
  static_assert(sizeof(multiple_inheritance_method_pointer) == 16,
                "Unexpected sizeof(multiple_inheritance_method_pointer).");
  static_assert(sizeof(virtual_inheritance_method_pointer) == 16,
                "Unexpected sizeof(virtual_inheritance_method_pointer).");
#endif
  void (IncompleteClass::*incomplete_class_method_pointer)();
  static_assert(sizeof(incomplete_class_method_pointer) >=
                    sizeof(virtual_inheritance_method_pointer),
                "Failed invariant: sizeof(incomplete_class_method_pointer) >= "
                "sizeof(virtual_inheritance_method_pointer)!");
}

class Callback {
  bool x = true;

 public:
  Callback() {}
  bool method() {
    x = !x;
    return x;
  }
};

class M2 {
  bool x = true;

 public:
  M2() {}
  bool method2() {
    x = !x;
    return x;
  }
};

class MultipleInheritance : public Callback, public M2 {};

TEST(MutexMethodPointerTest, ConditionWithMultipleInheritanceMethod) {
  // This test ensures that Condition can deal with method pointers from classes
  // with multiple inheritance.
  MultipleInheritance object = MultipleInheritance();
  absl::Condition condition(&object, &MultipleInheritance::method);
  EXPECT_FALSE(condition.Eval());
  EXPECT_TRUE(condition.Eval());
}

class __virtual_inheritance VirtualInheritance : virtual public Callback {
  bool x = false;

 public:
  VirtualInheritance() {}
  bool method() {
    x = !x;
    return x;
  }
};

TEST(MutexMethodPointerTest, ConditionWithVirtualInheritanceMethod) {
  // This test ensures that Condition can deal with method pointers from classes
  // with virtual inheritance.
  VirtualInheritance object = VirtualInheritance();
  absl::Condition condition(&object, &VirtualInheritance::method);
  EXPECT_TRUE(condition.Eval());
  EXPECT_FALSE(condition.Eval());
}
#endif  // #ifdef _MSC_VER

TEST(MutexMethodPointerTest, ConditionWithIncompleteClassMethod) {
  using IncompleteClassMethodPointer = void (IncompleteClass::*)();

  union CallbackSlot {
    void (*anonymous_function_pointer)();
    IncompleteClassMethodPointer incomplete_class_method_pointer;
  };

  static_assert(sizeof(CallbackSlot) >= sizeof(IncompleteClassMethodPointer),
                "The callback slot is not big enough for method pointers.");
  static_assert(
      sizeof(CallbackSlot) == sizeof(IncompleteClassMethodPointer),
      "The callback slot is not big enough for anonymous function pointers.");

#if defined(_MSC_VER)
  static_assert(sizeof(IncompleteClassMethodPointer) <= 24,
                "The pointer to a method of an incomplete class is too big.");
#endif
}

}  // namespace