166de1283SSergey Makeev // The MIT License (MIT)
266de1283SSergey Makeev //
366de1283SSergey Makeev // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
466de1283SSergey Makeev //
566de1283SSergey Makeev // 	Permission is hereby granted, free of charge, to any person obtaining a copy
666de1283SSergey Makeev // 	of this software and associated documentation files (the "Software"), to deal
766de1283SSergey Makeev // 	in the Software without restriction, including without limitation the rights
866de1283SSergey Makeev // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
966de1283SSergey Makeev // 	copies of the Software, and to permit persons to whom the Software is
1066de1283SSergey Makeev // 	furnished to do so, subject to the following conditions:
1166de1283SSergey Makeev //
1266de1283SSergey Makeev //  The above copyright notice and this permission notice shall be included in
1366de1283SSergey Makeev // 	all copies or substantial portions of the Software.
1466de1283SSergey Makeev //
1566de1283SSergey Makeev // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1666de1283SSergey Makeev // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1766de1283SSergey Makeev // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1866de1283SSergey Makeev // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1966de1283SSergey Makeev // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2066de1283SSergey Makeev // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2166de1283SSergey Makeev // 	THE SOFTWARE.
2266de1283SSergey Makeev 
2366de1283SSergey Makeev #pragma once
2466de1283SSergey Makeev 
25*02d170cfSs.makeev_local #include <MTConfig.h>
2666de1283SSergey Makeev 
27*02d170cfSs.makeev_local #if MT_MSVC_COMPILER_FAMILY
2866de1283SSergey Makeev #include <Platform/Windows/MTAtomic.h>
29*02d170cfSs.makeev_local #elif MT_PLATFORM_POSIX || MT_PLATFORM_OSX
3066de1283SSergey Makeev #include <Platform/Posix/MTAtomic.h>
31*02d170cfSs.makeev_local #else
3266de1283SSergey Makeev #endif
3366de1283SSergey Makeev 
3466de1283SSergey Makeev 
3566de1283SSergey Makeev 
3666de1283SSergey Makeev namespace MT
3766de1283SSergey Makeev {
3827dbb6f7Ss.makeev 	inline bool IsPointerAligned( const volatile void* p, const uint32 align )
3927dbb6f7Ss.makeev 	{
4027dbb6f7Ss.makeev 		return !((uintptr_t)p & (align - 1));
4127dbb6f7Ss.makeev 	}
4227dbb6f7Ss.makeev 
4327dbb6f7Ss.makeev 
4466de1283SSergey Makeev 	//compile time POD type check
4566de1283SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4666de1283SSergey Makeev 	static_assert(std::is_pod<AtomicInt32Base>::value == true, "AtomicInt32Base must be a POD (plain old data type)");
4766de1283SSergey Makeev 
4866de1283SSergey Makeev 
4966de1283SSergey Makeev 	//
5066de1283SSergey Makeev 	// Atomic int (type with constructor)
5166de1283SSergey Makeev 	//
5266de1283SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5366de1283SSergey Makeev 	class AtomicInt32 : public AtomicInt32Base
5466de1283SSergey Makeev 	{
5566de1283SSergey Makeev 
5666de1283SSergey Makeev 	public:
5766de1283SSergey Makeev 
5866de1283SSergey Makeev 		AtomicInt32()
5966de1283SSergey Makeev 		{
6066de1283SSergey Makeev 			_value = 0;
6166de1283SSergey Makeev 			static_assert(sizeof(AtomicInt32) == 4, "Invalid type size");
6266de1283SSergey Makeev 			MT_ASSERT(IsPointerAligned(&_value, 4), "Invalid atomic int alignment");
6366de1283SSergey Makeev 		}
6466de1283SSergey Makeev 
6566de1283SSergey Makeev 		explicit AtomicInt32(int v)
6666de1283SSergey Makeev 		{
6766de1283SSergey Makeev 			_value = v;
6866de1283SSergey Makeev 			static_assert(sizeof(AtomicInt32) == 4, "Invalid type size");
6966de1283SSergey Makeev 			MT_ASSERT(IsPointerAligned(&_value, 4), "Invalid atomic int alignment");
7066de1283SSergey Makeev 		}
7166de1283SSergey Makeev 	};
7266de1283SSergey Makeev 
7366de1283SSergey Makeev 
7466de1283SSergey Makeev 	//compile time POD type check
7566de1283SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7666de1283SSergey Makeev 	static_assert(std::is_pod<AtomicPtrBase>::value == true, "AtomicPtrBase must be a POD (plain old data type)");
7766de1283SSergey Makeev 
7866de1283SSergey Makeev 
7966de1283SSergey Makeev 	//
8066de1283SSergey Makeev 	// Atomic pointer (type with constructor)
8166de1283SSergey Makeev 	//
8266de1283SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8366de1283SSergey Makeev 	template<typename T>
8466de1283SSergey Makeev 	class AtomicPtr : protected AtomicPtrBase
8566de1283SSergey Makeev 	{
8666de1283SSergey Makeev 	public:
8766de1283SSergey Makeev 		AtomicPtr()
8866de1283SSergey Makeev 		{
8966de1283SSergey Makeev 			_value = nullptr;
9066de1283SSergey Makeev 			MT_ASSERT(IsPointerAligned(&_value, sizeof(void*)), "Invalid atomic ptr alignment");
9166de1283SSergey Makeev 		}
9266de1283SSergey Makeev 
9366de1283SSergey Makeev 		explicit AtomicPtr(T* v)
9466de1283SSergey Makeev 		{
9566de1283SSergey Makeev 			_value = v;
9666de1283SSergey Makeev 			MT_ASSERT(IsPointerAligned(&_value, sizeof(void*)), "Invalid atomic ptr alignment");
9766de1283SSergey Makeev 		}
9866de1283SSergey Makeev 
9966de1283SSergey Makeev 		T* Load() const
10066de1283SSergey Makeev 		{
10166de1283SSergey Makeev 			return (T*)AtomicPtrBase::Load();
10266de1283SSergey Makeev 		}
10366de1283SSergey Makeev 
10466de1283SSergey Makeev 		T* Store(T* val)
10566de1283SSergey Makeev 		{
10666de1283SSergey Makeev 			return (T*)AtomicPtrBase::Store(val);
10766de1283SSergey Makeev 		}
10866de1283SSergey Makeev 
10966de1283SSergey Makeev 
11066de1283SSergey Makeev 		T* CompareAndSwap(T* compareValue, T* newValue)
11166de1283SSergey Makeev 		{
11266de1283SSergey Makeev 			return (T*)AtomicPtrBase::CompareAndSwap(compareValue, newValue);
11366de1283SSergey Makeev 		}
11466de1283SSergey Makeev 
11566de1283SSergey Makeev 		T* LoadRelaxed() const
11666de1283SSergey Makeev 		{
11766de1283SSergey Makeev 			return (T*)AtomicPtrBase::LoadRelaxed();
11866de1283SSergey Makeev 		}
11966de1283SSergey Makeev 
12066de1283SSergey Makeev 		void StoreRelaxed(T* val)
12166de1283SSergey Makeev 		{
12266de1283SSergey Makeev 			AtomicPtrBase::StoreRelaxed(val);
12366de1283SSergey Makeev 		}
12466de1283SSergey Makeev 	};
12566de1283SSergey Makeev }