#include <iostream>
using namespace std;

class Student
{
private:
  // packing student info in 2 bytes:
  //
  // 15   13    8  7   3  2  10    <- bit positions
  //  xx   gggggg  ccccc  m  yy
  //
  // Year    in  bits  0..1:  2 bits for 4 options  (00, 01, 10, 11: need to adjust +1)
  // Major   in  bit      2:  1 bits for 2 options  (T/F)
  // Credits in  bits  3..6:  5 bits for 32 options (0..31: need to adjust +1)
  // GPA     in  bits 8..13:  6 bits for 44 options (0..43)
  //
  // bits 14 and 15 are not used  
  
  unsigned short data;
  

public:
  Student() : data(0)
  {
  }

  Student( int year, int credits ) : data(0)
  {
    setYear( year );
    setCredits( credits );
  }

  int getYear()
  {
    unsigned short mask = 0x0003;      // or 0b0000.0000.0000.0011

    unsigned short year = data & mask; // extract only last two bits, rest are 0

    return year + 1;                   // convert 0,1,2,3 back to 1,2,3,4
  }


  int getCredits()
  {
    unsigned short mask = 0x001F;          // or   0b0000.0000.0001.1111  (5 bits)
    
    mask = mask << 3;                      //        0000.0000.1111.1000
                                           // move by 3 to position under bits 3..7

    unsigned short credits = data & mask;  // sample data: 0000101101101010 &
                                           //        mask: ........11111000   <- . for 0, less clutter
                                           //     credits: 0000000001101000 = 13*2^3

    credits = credits >> 3;                //     credits: 0000000000001101 = 13
                                           // move by 3 to position to beginning    

    credits--;                             // adjust credits

    return credits;
  }

  void setYear( int year )
  {
    unsigned short mask = 0x0003; // or 0b0000.0000.0000.0011

                                  // sample data: 0000101101101001 & <- "multiply"
    data = data & ~mask;          //       ~mask: 1111111111111100   <- "1 keep, 0 clear
                                  //        data: 0000101101101000

    year = year - 1;              // convert 1,2,3,4, i.e. 01, 10, 11, 100
                                  // into    0,1,2,3, i.e. 00, 01, 10, 11
    
    data = data | year;           // data: 0000101101101000 |
                                  // year: ..............10   <- . for 0, less clutter
				  // data: 0000101101101010
  }

  void setCredits( int credits )
  {
    unsigned short mask = 0x001F; // or   0b0000.0000.0001.1111  (5 bits)
    mask = mask << 3;             // move by 3 to position under bits 3..7
                                  //      0b0000.0000.1111.1000
    mask = ~mask;                 // flip 0b1111.1111.0000.0111
                                  // so desired 5 bits cleared, rest kept, when "multiply" with &

                                  // sample data: 0000101101101001 & <- "multiply"
    data = data & mask;           //        mask: 1111111100000111
                                  //        data: 00001011.....001 & <- . for 0

    credits++;                    // adjust credits

    credits = credits << 3;       // move by 3 to position under bits 3..7
                                  // new credits: ........10110...
      
    data = data | credits;        //    data: 00001011 ..... 001 | <- add with 0s to keep rest
                                  // credits: ........ 10110 ...   <- . for 0
				  //    data: 00001011 10110 001
  }

  void print()
  {
    cout << "Student details:" << endl
	 << "- year   : " << getYear() << endl
	 << "- credits: " << getCredits() << endl;
      // << "- major  : " << getMajor() << endl
      // << "- gpa    : " << getGPA() << endl;
  }
};


int main()
{
  Student s1;              // calls default c-tor
  Student s2( 1, 25 );     // calls 2nd c-tor

  s1.print();
  s2.print();
					 
  s1.setYear(2);
  cout << s1.getYear() << endl;

  s1.setCredits(17);
  cout << s1.getCredits() << endl;

  s1.print();

  s1.setYear(3);
  cout << s1.getYear() << endl;

  s1.setCredits(23);
  cout << s1.getCredits() << endl;
  
  s1.print();
}