#include <iostream>
#include <vector>
#include <atomic>
#include <thread>


class CircularBuffer {


  private:
  std::vector<int> buffer;
  int max_capacity;
  std::atomic<int> head;
  std::atomic<int> tail;


  public:
  CircularBuffer(int max_capacity) : max_capacity(max_capacity), head(0), tail(0){
    // this-> max_capacity = max_capacity;
    // this-> head = 0;
    // this-> tail = 0;
    buffer.resize(max_capacity);
  }



  bool push_back(int element)
  {
       
        int curr_tail = tail.load(std::memory_order_seq_cst);
        int next_tail = (curr_tail+1) % max_capacity;

        if ( next_tail == head.load(std::memory_order_seq_cst))
        {
            return false;
        }
        buffer[curr_tail] = element;
        tail.store(next_tail, std::memory_order_seq_cst);
        return true;
        }
  

  bool pop_front(int& element)
  {
    int curr_head = head.load(std::memory_order_seq_cst);
    if (curr_head == tail.load(std::memory_order_seq_cst)){
        return false;    }
  
     element = buffer[curr_head];
     head.store((curr_head + 1 ) % max_capacity, std::memory_order_seq_cst);

    std::cout << element << std::endl;

    return true;
  }

   bool is_empty()
    {
        return head.load(std::memory_order_seq_cst) == tail.load(std::memory_order_seq_cst);
    }

        bool is_full()
    {
        return ((tail.load(std::memory_order_seq_cst) + 1) % max_capacity) == head.load(std::memory_order_seq_cst);

    }
  };



   

//     bool head_ahead()
//     {
//         return tail+1 ==head;
//     }

//     bool tail_ahead()
//     {
//         return head+1==tail;
//     }



//     bool was_full()
//     {
//         return head > tail && last_piece;
//     }

//     bool last_piece()
    
//     {
//         return head == max_capacity;

//     }

//     bool start_over()
//     {
//         return is_full && head != 0;
//     }
    



int main()
{
    CircularBuffer buf(5);

    std::thread producer([&buf]() {
        for (int i = 1; i <= 10; ++i) {
            while (!buf.push_back(i)) {
                std::this_thread::yield(); 
            }
            std::cout << "Produced: " << i << std::endl;
        }
    });

   std::thread consumer([&buf]() {
        for (int i = 1; i <= 10; ++i) {
            int item;
            while (!buf.pop_front(item)) {
                std::this_thread::yield(); 
            }
            std::cout << "Consumed: " << item << std::endl;
        }
    }); 

    producer.join();
    consumer.join();


    return 0;
}