//#####################################################################
// Copyright 2012.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYREGHT.txt.
//#####################################################################
// Class CODE_BLOCK
//#####################################################################
#ifndef __CODE_BLOCK__
#define __CODE_BLOCK__

#include <Core/Data_Structures/HASHTABLE.h>
#include <Core/Symbolics/INSTRUCTION.h>
#include <list>
namespace PhysBAM{

struct INSTRUCTION;

struct CODE_BLOCK
{
    typedef std::pair<CODE_BLOCK*,std::list<INSTRUCTION>::iterator> INST_IT;

    CODE_BLOCK *prev[2]={},*next[2]={};
    std::list<INSTRUCTION> insts;
    MEM_LABEL id{-1};

    void Merge_Code(CODE_BLOCK* cb);

    auto begin() {return insts.begin();}
    auto end() {return insts.end();}
    auto begin() const {return insts.begin();}
    auto end() const {return insts.end();}
    auto rbegin() {return insts.rbegin();}
    auto rend() {return insts.rend();}
    auto cbegin() {return insts.cbegin();}
    auto cend() {return insts.cend();}

    struct ITERATOR
    {
        typedef std::pair<CODE_BLOCK*,std::list<INSTRUCTION>::iterator> T_PAIR;
        T_PAIR pr={nullptr,{}};
        ITERATOR() = default;
        ITERATOR(CODE_BLOCK* B,std::list<INSTRUCTION>::iterator i):pr{B,i}{}
        ITERATOR& operator++() {++pr.second;return *this;}
        ITERATOR operator++(int) {auto t=*this;++pr.second;return t;}
        ITERATOR& operator--() {--pr.second;return *this;}
        ITERATOR operator--(int) {auto t=*this;--pr.second;return t;}
        T_PAIR& operator*() {return pr;}
        const T_PAIR& operator*() const {return pr;}
        T_PAIR* operator->() {return &pr;}
        const T_PAIR* operator->() const {return &pr;}
        bool operator==(const ITERATOR& a) const {return pr==a.pr;}
    };

    ITERATOR Begin_It() {return {this,insts.begin()};}
    ITERATOR End_It() {return {this,insts.end()};}
    ITERATOR Last_It() {return {this,std::prev(insts.end())};}
};

std::ostream& operator<<(std::ostream& o,const std::pair<CODE_BLOCK*,std::list<INSTRUCTION>::iterator>& it);
std::ostream& operator<<(std::ostream& o,const CODE_BLOCK::ITERATOR& it);

}
#endif
