// ZPR - zadanie dodatkowe
// Autor: Aleksandra Jamróz

// Nagłówek <bit> wprowadzony w standardzie c++20: jego funkcje oraz zastosowania.

// Nagłówek <bit> wprowadzony w standardzie c++20 zawiera jeden typ oraz 13 funkcj do
// manipulowania oraz przetwarzania pojedynczych bitów oraz ich ciągów. Jest częścią
// bibloteki <numeric>.

// Do testowania funkcji korzystałam z kompilatora gcc 12.1
// Minimalna wersja kompilatora potrzebna do obsługi nagłówka: gcc 11

#include <bit>
#include <iostream>
#include <bitset>

using namespace std;

int main() {

// TYP

// std::endian:
// - std::endian::little - oznacza użycie porządku little endian
// - std::endian::big - oznacza użycie porządku big endian
// - std::endian::native - służy do wykrycia porządku aktualnej implementacji.


cout << "Sprawdzenie porządku wartości zwracanej" << endl;

if (std::endian::native == std::endian::big) {
        std::cout << "This machine uses big-endian byte order." << std::endl;
    } else if (std::endian::native == std::endian::little) {
        std::cout << "This machine uses little-endian byte order." << std::endl;
    } else {
        std::cout << "Byte order is unknown." << std::endl;
    }

// FUNKCJE

// std::bit_cast - reinterpretuje reprezentację obiektu jednego typu jako reprezentację innego typu.
// Innymi słowy - ciąg bitów pozostaje ten sam, jego interpretacja się zmienia.

cout << "\nFunkcja bit_cast" << endl;
uint i = 0b00001010;
cout << "Typ integer: " << i << endl;
float j = bit_cast<float>(i);
cout << "Liczba skonwertowana na typ float: " << j << endl;
cout << "Liczba skonwertowana z powrotem na typ integer: " << bit_cast<u_int>(j) << endl;


// std::has_single_bit - sprawdza, czy liczba jest potęgą dwójki

cout << "\nFunkcja has_single_bit" << endl;
const u_long z = 16;
const u_long y = 28;
cout << "Czy " << z << " jest potęgą 2? - " << ((has_single_bit(z)) ? "Tak" : "Nie") << endl;
cout << "Czy " << y << " jest potęgą 2? - " << ((has_single_bit(y)) ? "Tak" : "Nie") << endl;


// std::bit_ceil - znajduje najmniejszą całkową potęgę dwójki nie mniejszą od danej wartości
// std::bit_floor - znajduje największą całkową potęgę dwójki nie większą od podanej wartości

cout << "\nFunkcje bit_ceil oraz bit_floor" << endl;
cout << "Największa potęga 2 nie większa niż " << y << ": " << bit_floor(y) << endl;
cout << "Najmniejsza potęga 2 nie mniejsza niż " << y << ": " << bit_ceil(y) << endl;


//std:: bit_width - znajduje najmniejszą liczbę bitów potrzebnych do reprezentacji danej wartości

cout << "\nFunkcja bit_width" << endl;
cout << "Najmniejsza liczba bitów potrzebna do reprezentacji liczby " << z << ": " << bit_width(z) <<endl;
cout << "Zapis w systemie dwójkowym: " << bitset<8>(z) << endl;
cout << "Najmniejsza liczba bitów potrzebna do reprezentacji liczby " << y << ": " << bit_width(y) <<endl;
cout << "Zapis w systemie dwójkowym: " << bitset<8>(y) << endl;
cout << "Najmniejsza liczba bitów potrzebna do reprezentacji liczby " << i << ": " << bit_width(i) <<endl;
cout << "Zapis w systemie dwójkowym: " << bitset<8>(i) << endl;

// std::rotl - oblicza wynik bitowego obrócenia w lewo
// std::rotr - oblicza wynik bitowego obrócenia w prawo

cout << "\nFunkcje rotl oraz rotr" << endl;
const uint8_t bin = 0b00011101;
cout << "Liczba wyjściowa: " << std::bitset<8>(bin) << endl;
cout << "Obrót w lewo o 1: " << std::bitset<8>(std::rotl(bin,1)) << endl;
cout << "Obrót w lewo o 2: " << std::bitset<8>(std::rotl(bin,2)) << endl;
cout << "Liczba wyjściowa : " << std::bitset<8>(bin) << endl;
cout << "Obrót w prawo o 1: " << std::bitset<8>(std::rotr(bin,1)) << endl;
cout << "Obrót w prawo o 2: " << std::bitset<8>(std::rotr(bin,2)) << endl;


// std::countl_zero - liczy liczbę kolejnych bitów "0", zaczynając od najbardziej znaczącego bitu
// std::countl_one - liczy liczbę kolejnych bitów "1", zaczynając od najbardziej znaczącego bitu

cout << "\nFunkcje countl_zero oraz countl_one" << endl;
const uint8_t bin1 = 0b00001110;
cout << "\nLiczba wyjściowa: " << std::bitset<8>(bin1) << endl;
cout << "Liczba zer począwszy od najbardziej znaczącego bitu: " << countl_zero(bin1) << endl;
cout << "Liczba jedynek począwszy od najbardziej znaczącego bitu: " << countl_one(bin1) << endl;
const uint8_t bin2 = 0b11000011;
cout << "\nLiczba wyjściowa: " << std::bitset<8>(bin2) << endl;
cout << "Liczba zer począwszy od najbardziej znaczącego bitu: " << countl_zero(bin2) << endl;
cout << "Liczba jedynek począwszy od najbardziej znaczącego bitu: " << countl_one(bin2) << endl;


// std::countr_zero - liczy liczbę kolejnych bitów "0", zaczynając od najmniej znaczącego bitu
// std::countr_one - liczy liczbę kolejnych bitów "1", zaczynając od najmniej znaczącego bitu

cout << "\nFunkcje countr_zero oraz countr_one" << endl;
const uint8_t bin3 = 0b01011100;
cout << "\nLiczba wyjściowa: " << std::bitset<8>(bin3) << endl;
cout << "Liczba zer począwszy od najmniej znaczącego bitu: " << countr_zero(bin3) << endl;
cout << "Liczba jedynek począwszy od najmniej znaczącego bitu: " << countr_one(bin3) << endl;
const uint8_t bin4 = 0b11000011;
cout << "\nLiczba wyjściowa: " << std::bitset<8>(bin4) << endl;
cout << "Liczba zer począwszy od najmniej znaczącego bitu: " << countr_zero(bin4) << endl;
cout << "Liczba jedynek począwszy od najmniej znaczącego bitu: " << countr_one(bin4) << endl;


// std::popcount - liczy liczbę bitów "1" w liczbie całkowitej bez znaku

cout << "\nFunkcja popcount" << endl;
cout << "Liczba wyjściowa: " << std::bitset<8>(bin3) << endl;
cout << "Liczba jedynek: " << popcount(bin3) << endl;
cout << "\nLiczba wyjściowa: " << std::bitset<8>(bin4) << endl;
cout << "Liczba jedynek: " << popcount(bin4) << endl;


return 0;
}


// Źródła:
// - https://iq.opengenus.org/bit-header-file-in-cpp20/
// - https://en.cppreference.com/w/cpp/header/bit
