forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			189 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "mozilla/Assertions.h"
 | |
| #include "mozilla/AtomicBitfields.h"
 | |
| 
 | |
| // This is a big macro mess, so let's summarize what's in here right up front:
 | |
| //
 | |
| // |TestDocumentationExample| is intended to be a copy-paste of the example
 | |
| // in the macro's documentation, to make sure it's correct.
 | |
| //
 | |
| //
 | |
| // |TestJammedWithFlags| tests using every bit of the type for bool flags.
 | |
| // 64-bit isn't tested due to macro limitations.
 | |
| //
 | |
| //
 | |
| // |TestLopsided| tests an instance with the following configuration:
 | |
| //
 | |
| // * a 1-bit boolean
 | |
| // * an (N-1)-bit uintN_t
 | |
| //
 | |
| // It tests both orderings of these fields.
 | |
| //
 | |
| // Hopefully these are enough to cover all the nasty boundary conditions
 | |
| // (that still compile).
 | |
| 
 | |
| // ==================== TestDocumentationExample ========================
 | |
| 
 | |
| struct MyType {
 | |
|   MOZ_ATOMIC_BITFIELDS(mAtomicFields, 8,
 | |
|                        ((bool, IsDownloaded, 1), (uint32_t, SomeData, 2),
 | |
|                         (uint8_t, OtherData, 5)))
 | |
| 
 | |
|   int32_t aNormalInteger;
 | |
| 
 | |
|   explicit MyType(uint32_t aSomeData) : aNormalInteger(7) {
 | |
|     StoreSomeData(aSomeData);
 | |
|     // Other bitfields were already default initialized to 0/false
 | |
|   }
 | |
| };
 | |
| 
 | |
| void TestDocumentationExample() {
 | |
|   MyType val(3);
 | |
| 
 | |
|   if (!val.LoadIsDownloaded()) {
 | |
|     val.StoreOtherData(2);
 | |
|     val.StoreIsDownloaded(true);
 | |
|   }
 | |
| }
 | |
| 
 | |
| // ====================== TestJammedWithFlags =========================
 | |
| 
 | |
| #define TIMES_8(aFunc, aSeparator, aArgs) \
 | |
|   MOZ_FOR_EACH_SEPARATED(aFunc, aSeparator, aArgs, (1, 2, 3, 4, 5, 6, 7, 8))
 | |
| #define TIMES_16(aFunc, aSeparator, aArgs) \
 | |
|   MOZ_FOR_EACH_SEPARATED(                  \
 | |
|       aFunc, aSeparator, aArgs,            \
 | |
|       (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16))
 | |
| #define TIMES_32(aFunc, aSeparator, aArgs)                                    \
 | |
|   MOZ_FOR_EACH_SEPARATED(                                                     \
 | |
|       aFunc, aSeparator, aArgs,                                               \
 | |
|       (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))
 | |
| 
 | |
| #define CHECK_BOOL(aIndex)                     \
 | |
|   MOZ_ASSERT(val.LoadFlag##aIndex() == false); \
 | |
|   val.StoreFlag##aIndex(true);                 \
 | |
|   MOZ_ASSERT(val.LoadFlag##aIndex() == true);  \
 | |
|   val.StoreFlag##aIndex(false);                \
 | |
|   MOZ_ASSERT(val.LoadFlag##aIndex() == false);
 | |
| 
 | |
| #define GENERATE_TEST_JAMMED_WITH_FLAGS(aSize) \
 | |
|   void TestJammedWithFlags##aSize() {          \
 | |
|     JammedWithFlags##aSize val;                \
 | |
|     TIMES_##aSize(CHECK_BOOL, (;), ());        \
 | |
|   }
 | |
| 
 | |
| #define TEST_JAMMED_WITH_FLAGS(aSize) TestJammedWithFlags##aSize();
 | |
| 
 | |
| // ========================= TestLopsided ===========================
 | |
| 
 | |
| #define GENERATE_TEST_LOPSIDED_FUNC(aSide, aSize)          \
 | |
|   void TestLopsided##aSide##aSize() {                      \
 | |
|     Lopsided##aSide##aSize val;                            \
 | |
|     MOZ_ASSERT(val.LoadHappyLittleBit() == false);         \
 | |
|     MOZ_ASSERT(val.LoadLargeAndInCharge() == 0);           \
 | |
|     val.StoreHappyLittleBit(true);                         \
 | |
|     MOZ_ASSERT(val.LoadHappyLittleBit() == true);          \
 | |
|     MOZ_ASSERT(val.LoadLargeAndInCharge() == 0);           \
 | |
|     val.StoreLargeAndInCharge(1);                          \
 | |
|     MOZ_ASSERT(val.LoadHappyLittleBit() == true);          \
 | |
|     MOZ_ASSERT(val.LoadLargeAndInCharge() == 1);           \
 | |
|     val.StoreLargeAndInCharge(0);                          \
 | |
|     MOZ_ASSERT(val.LoadHappyLittleBit() == true);          \
 | |
|     MOZ_ASSERT(val.LoadLargeAndInCharge() == 0);           \
 | |
|     uint##aSize##_t size = aSize;                          \
 | |
|     uint##aSize##_t int_max = (~(1ull << (size - 1))) - 1; \
 | |
|     val.StoreLargeAndInCharge(int_max);                    \
 | |
|     MOZ_ASSERT(val.LoadHappyLittleBit() == true);          \
 | |
|     MOZ_ASSERT(val.LoadLargeAndInCharge() == int_max);     \
 | |
|     val.StoreHappyLittleBit(false);                        \
 | |
|     MOZ_ASSERT(val.LoadHappyLittleBit() == false);         \
 | |
|     MOZ_ASSERT(val.LoadLargeAndInCharge() == int_max);     \
 | |
|     val.StoreLargeAndInCharge(int_max);                    \
 | |
|     MOZ_ASSERT(val.LoadHappyLittleBit() == false);         \
 | |
|     MOZ_ASSERT(val.LoadLargeAndInCharge() == int_max);     \
 | |
|   }
 | |
| 
 | |
| #define GENERATE_TEST_LOPSIDED(aSize)                                        \
 | |
|   struct LopsidedA##aSize {                                                  \
 | |
|     MOZ_ATOMIC_BITFIELDS(mAtomicFields, aSize,                               \
 | |
|                          ((bool, HappyLittleBit, 1),                         \
 | |
|                           (uint##aSize##_t, LargeAndInCharge, ((aSize)-1)))) \
 | |
|   };                                                                         \
 | |
|   struct LopsidedB##aSize {                                                  \
 | |
|     MOZ_ATOMIC_BITFIELDS(mAtomicFields, aSize,                               \
 | |
|                          ((uint##aSize##_t, LargeAndInCharge, ((aSize)-1)),  \
 | |
|                           (bool, HappyLittleBit, 1)))                        \
 | |
|   };                                                                         \
 | |
|   GENERATE_TEST_LOPSIDED_FUNC(A, aSize);                                     \
 | |
|   GENERATE_TEST_LOPSIDED_FUNC(B, aSize);
 | |
| 
 | |
| #define TEST_LOPSIDED(aSize) \
 | |
|   TestLopsidedA##aSize();    \
 | |
|   TestLopsidedB##aSize();
 | |
| 
 | |
| // ==================== generate and run the tests ======================
 | |
| 
 | |
| // There's an unknown bug in clang-cl-9 (used for win64-ccov) that makes
 | |
| // generating these with the TIMES_N macro not work. So these are written out
 | |
| // explicitly to unbork CI.
 | |
| struct JammedWithFlags8 {
 | |
|   MOZ_ATOMIC_BITFIELDS(mAtomicFields, 8,
 | |
|                        ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1),
 | |
|                         (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1),
 | |
|                         (bool, Flag7, 1), (bool, Flag8, 1)))
 | |
| };
 | |
| 
 | |
| struct JammedWithFlags16 {
 | |
|   MOZ_ATOMIC_BITFIELDS(mAtomicFields, 16,
 | |
|                        ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1),
 | |
|                         (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1),
 | |
|                         (bool, Flag7, 1), (bool, Flag8, 1), (bool, Flag9, 1),
 | |
|                         (bool, Flag10, 1), (bool, Flag11, 1), (bool, Flag12, 1),
 | |
|                         (bool, Flag13, 1), (bool, Flag14, 1), (bool, Flag15, 1),
 | |
|                         (bool, Flag16, 1)))
 | |
| };
 | |
| 
 | |
| struct JammedWithFlags32 {
 | |
|   MOZ_ATOMIC_BITFIELDS(mAtomicFields, 32,
 | |
|                        ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1),
 | |
|                         (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1),
 | |
|                         (bool, Flag7, 1), (bool, Flag8, 1), (bool, Flag9, 1),
 | |
|                         (bool, Flag10, 1), (bool, Flag11, 1), (bool, Flag12, 1),
 | |
|                         (bool, Flag13, 1), (bool, Flag14, 1), (bool, Flag15, 1),
 | |
|                         (bool, Flag16, 1), (bool, Flag17, 1), (bool, Flag18, 1),
 | |
|                         (bool, Flag19, 1), (bool, Flag20, 1), (bool, Flag21, 1),
 | |
|                         (bool, Flag22, 1), (bool, Flag23, 1), (bool, Flag24, 1),
 | |
|                         (bool, Flag25, 1), (bool, Flag26, 1), (bool, Flag27, 1),
 | |
|                         (bool, Flag28, 1), (bool, Flag29, 1), (bool, Flag30, 1),
 | |
|                         (bool, Flag31, 1), (bool, Flag32, 1)))
 | |
| };
 | |
| 
 | |
| GENERATE_TEST_JAMMED_WITH_FLAGS(8)
 | |
| GENERATE_TEST_JAMMED_WITH_FLAGS(16)
 | |
| GENERATE_TEST_JAMMED_WITH_FLAGS(32)
 | |
| // MOZ_FOR_EACH_64 doesn't exist :(
 | |
| 
 | |
| GENERATE_TEST_LOPSIDED(8)
 | |
| GENERATE_TEST_LOPSIDED(16)
 | |
| GENERATE_TEST_LOPSIDED(32)
 | |
| GENERATE_TEST_LOPSIDED(64)
 | |
| 
 | |
| int main() {
 | |
|   TestDocumentationExample();
 | |
| 
 | |
|   TEST_JAMMED_WITH_FLAGS(8);
 | |
|   TEST_JAMMED_WITH_FLAGS(16);
 | |
|   TEST_JAMMED_WITH_FLAGS(32);
 | |
| 
 | |
|   TEST_LOPSIDED(8);
 | |
|   TEST_LOPSIDED(16);
 | |
|   TEST_LOPSIDED(32);
 | |
|   TEST_LOPSIDED(64);
 | |
|   return 0;
 | |
| }
 | 
