text: #pragma once
  #include <iostream>
  #include <vector>
  #include <bitset>
  #include <array>
  #include <string>
  #include <intrin.h>
  
  class InstructionSet
  {
  	// forward declarations
  	class InstructionSet_Internal;
  
  public:
  	// getters
  	static std::string Vendor( void ) {
  		return CPU_Rep.vendor_;
  	}
  	static std::string Brand( void ) {
  		return CPU_Rep.brand_;
  	}
  
  	static bool SSE3( void ) {
  		return CPU_Rep.f_1_ECX_[0];
  	}
  	static bool PCLMULQDQ( void ) {
  		return CPU_Rep.f_1_ECX_[1];
  	}
  	static bool MONITOR( void ) {
  		return CPU_Rep.f_1_ECX_[3];
  	}
  	static bool SSSE3( void ) {
  		return CPU_Rep.f_1_ECX_[9];
  	}
  	static bool FMA( void ) {
  		return CPU_Rep.f_1_ECX_[12];
  	}
  	static bool CMPXCHG16B( void ) {
  		return CPU_Rep.f_1_ECX_[13];
  	}
  	static bool SSE41( void ) {
  		return CPU_Rep.f_1_ECX_[19];
  	}
  	static bool SSE42( void ) {
  		return CPU_Rep.f_1_ECX_[20];
  	}
  	static bool MOVBE( void ) {
  		return CPU_Rep.f_1_ECX_[22];
  	}
  	static bool POPCNT( void ) {
  		return CPU_Rep.f_1_ECX_[23];
  	}
  	static bool AES( void ) {
  		return CPU_Rep.f_1_ECX_[25];
  	}
  	static bool XSAVE( void ) {
  		return CPU_Rep.f_1_ECX_[26];
  	}
  	static bool OSXSAVE( void ) {
  		return CPU_Rep.f_1_ECX_[27];
  	}
  	static bool AVX( void ) {
  		return CPU_Rep.f_1_ECX_[28];
  	}
  	static bool F16C( void ) {
  		return CPU_Rep.f_1_ECX_[29];
  	}
  	static bool RDRAND( void ) {
  		return CPU_Rep.f_1_ECX_[30];
  	}
  
  	static bool MSR( void ) {
  		return CPU_Rep.f_1_EDX_[5];
  	}
  	static bool CX8( void ) {
  		return CPU_Rep.f_1_EDX_[8];
  	}
  	static bool SEP( void ) {
  		return CPU_Rep.f_1_EDX_[11];
  	}
  	static bool CMOV( void ) {
  		return CPU_Rep.f_1_EDX_[15];
  	}
  	static bool CLFSH( void ) {
  		return CPU_Rep.f_1_EDX_[19];
  	}
  	static bool MMX( void ) {
  		return CPU_Rep.f_1_EDX_[23];
  	}
  	static bool FXSR( void ) {
  		return CPU_Rep.f_1_EDX_[24];
  	}
  	static bool SSE( void ) {
  		return CPU_Rep.f_1_EDX_[25];
  	}
  	static bool SSE2( void ) {
  		return CPU_Rep.f_1_EDX_[26];
  	}
  
  	static bool FSGSBASE( void ) {
  		return CPU_Rep.f_7_EBX_[0];
  	}
  	static bool BMI1( void ) {
  		return CPU_Rep.f_7_EBX_[3];
  	}
  	static bool HLE( void ) {
  		return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[4];
  	}
  	static bool AVX2( void ) {
  		return CPU_Rep.f_7_EBX_[5];
  	}
  	static bool BMI2( void ) {
  		return CPU_Rep.f_7_EBX_[8];
  	}
  	static bool ERMS( void ) {
  		return CPU_Rep.f_7_EBX_[9];
  	}
  	static bool INVPCID( void ) {
  		return CPU_Rep.f_7_EBX_[10];
  	}
  	static bool RTM( void ) {
  		return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[11];
  	}
  	static bool AVX512F( void ) {
  		return CPU_Rep.f_7_EBX_[16];
  	}
  	static bool RDSEED( void ) {
  		return CPU_Rep.f_7_EBX_[18];
  	}
  	static bool ADX( void ) {
  		return CPU_Rep.f_7_EBX_[19];
  	}
  	static bool AVX512PF( void ) {
  		return CPU_Rep.f_7_EBX_[26];
  	}
  	static bool AVX512ER( void ) {
  		return CPU_Rep.f_7_EBX_[27];
  	}
  	static bool AVX512CD( void ) {
  		return CPU_Rep.f_7_EBX_[28];
  	}
  	static bool SHA( void ) {
  		return CPU_Rep.f_7_EBX_[29];
  	}
  
  	static bool PREFETCHWT1( void ) {
  		return CPU_Rep.f_7_ECX_[0];
  	}
  
  	static bool LAHF( void ) {
  		return CPU_Rep.f_81_ECX_[0];
  	}
  	static bool LZCNT( void ) {
  		return CPU_Rep.isIntel_ && CPU_Rep.f_81_ECX_[5];
  	}
  	static bool ABM( void ) {
  		return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[5];
  	}
  	static bool SSE4a( void ) {
  		return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[6];
  	}
  	static bool XOP( void ) {
  		return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[11];
  	}
  	static bool TBM( void ) {
  		return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[21];
  	}
  
  	static bool SYSCALL( void ) {
  		return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[11];
  	}
  	static bool MMXEXT( void ) {
  		return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[22];
  	}
  	static bool RDTSCP( void ) {
  		return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[27];
  	}
  	static bool _3DNOWEXT( void ) {
  		return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[30];
  	}
  	static bool _3DNOW( void ) {
  		return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31];
  	}
  
  private:
  	static const InstructionSet_Internal CPU_Rep;
  
  	class InstructionSet_Internal
  	{
  	public:
  		InstructionSet_Internal()
  			: nIds_ { 0 },
  			nExIds_ { 0 },
  			isIntel_ { false },
  			isAMD_ { false },
  			f_1_ECX_ { 0 },
  			f_1_EDX_ { 0 },
  			f_7_EBX_ { 0 },
  			f_7_ECX_ { 0 },
  			f_81_ECX_ { 0 },
  			f_81_EDX_ { 0 },
  			data_ {},
  			extdata_ {}
  		{
  			//int cpuInfo[4] = {-1};
  			std::array<int,4> cpui;
  
  			// Calling __cpuid with 0x0 as the function_id argument
  			// gets the number of the highest valid function ID.
  			__cpuid( cpui.data(),0 );
  			nIds_ = cpui[0];
  
  			for( int i = 0; i <= nIds_; ++i )
  			{
  				__cpuidex( cpui.data(),i,0 );
  				data_.push_back( cpui );
  			}
  
  			// Capture vendor string
  			char vendor[0x20];
  			memset( vendor,0,sizeof( vendor ) );
  			*reinterpret_cast<int*>( vendor ) = data_[0][1];
  			*reinterpret_cast<int*>( vendor + 4 ) = data_[0][3];
  			*reinterpret_cast<int*>( vendor + 8 ) = data_[0][2];
  			vendor_ = vendor;
  			if( vendor_ == "GenuineIntel" )
  			{
  				isIntel_ = true;
  			}
  			else if( vendor_ == "AuthenticAMD" )
  			{
  				isAMD_ = true;
  			}
  
  			// load bitset with flags for function 0x00000001
  			if( nIds_ >= 1 )
  			{
  				f_1_ECX_ = data_[1][2];
  				f_1_EDX_ = data_[1][3];
  			}
  
  			// load bitset with flags for function 0x00000007
  			if( nIds_ >= 7 )
  			{
  				f_7_EBX_ = data_[7][1];
  				f_7_ECX_ = data_[7][2];
  			}
  
  			// Calling __cpuid with 0x80000000 as the function_id argument
  			// gets the number of the highest valid extended ID.
  			__cpuid( cpui.data(),0x80000000 );
  			nExIds_ = cpui[0];
  
  			char brand[0x40];
  			memset( brand,0,sizeof( brand ) );
  
  			for( int i = 0x80000000; i <= nExIds_; ++i )
  			{
  				__cpuidex( cpui.data(),i,0 );
  				extdata_.push_back( cpui );
  			}
  
  			// load bitset with flags for function 0x80000001
  			if( nExIds_ >= 0x80000001 )
  			{
  				f_81_ECX_ = extdata_[1][2];
  				f_81_EDX_ = extdata_[1][3];
  			}
  
  			// Interpret CPU brand string if reported
  			if( nExIds_ >= 0x80000004 )
  			{
  				memcpy( brand,extdata_[2].data(),sizeof( cpui ) );
  				memcpy( brand + 16,extdata_[3].data(),sizeof( cpui ) );
  				memcpy( brand + 32,extdata_[4].data(),sizeof( cpui ) );
  				brand_ = brand;
  			}
  		};
  
  		int nIds_;
  		int nExIds_;
  		std::string vendor_;
  		std::string brand_;
  		bool isIntel_;
  		bool isAMD_;
  		std::bitset<32> f_1_ECX_;
  		std::bitset<32> f_1_EDX_;
  		std::bitset<32> f_7_EBX_;
  		std::bitset<32> f_7_ECX_;
  		std::bitset<32> f_81_ECX_;
  		std::bitset<32> f_81_EDX_;
  		std::vector<std::array<int,4>> data_;
  		std::vector<std::array<int,4>> extdata_;
  	};
  };