// File: CMU-SAFARI[P]ramulator/src/Scheduler.h
// Function: ramulator::Scheduler<ramulator::DDR3>::get_head(std::__cxx11::list<ramulator::Request, std::allocator<ramulator::Request>>&)
list<Request>::iterator get_head(list<Request>& q)
    {
        // TODO make the decision at compile time
        if (type != Type::FRFCFS_PriorHit) {
            //If queue is empty, return end of queue
            if (!q.size())
                return q.end();

            //Else return based on the policy
            auto head = q.begin();
            for (auto itr = next(q.begin(), 1); itr != q.end(); itr++)
                head = compare[int(type)](head, itr);

            return head;
        } 
        else { //Code to get around edge cases for FRFCFS_PriorHit
            
       //If queue is empty, return end of queue
            if (!q.size())
                return q.end();

       //Else return based on FRFCFS_PriorHit Scheduling Policy
            auto head = q.begin();
            for (auto itr = next(q.begin(), 1); itr != q.end(); itr++) {
                head = compare[int(Type::FRFCFS_PriorHit)](head, itr);
            }

            if (this->ctrl->is_ready(head) && this->ctrl->is_row_hit(head)) {
                return head;
            }

            // prepare a list of hit request
            vector<vector<int>> hit_reqs;
            for (auto itr = q.begin() ; itr != q.end() ; ++itr) {
                if (this->ctrl->is_row_hit(itr)) {
                    auto begin = itr->addr_vec.begin();
                    // TODO Here it assumes all DRAM standards use PRE to close a row
                    // It's better to make it more general.
                    auto end = begin + int(ctrl->channel->spec->scope[int(T::Command::PRE)]) + 1;
                    vector<int> rowgroup(begin, end); // bank or subarray
                    hit_reqs.push_back(rowgroup);
                }
            }
            // if we can't find proper request, we need to return q.end(),
            // so that no command will be scheduled
            head = q.end();
            for (auto itr = q.begin(); itr != q.end(); itr++) {
                bool violate_hit = false;
                if ((!this->ctrl->is_row_hit(itr)) && this->ctrl->is_row_open(itr)) {
                    // so the next instruction to be scheduled is PRE, might violate hit
                    auto begin = itr->addr_vec.begin();
                    // TODO Here it assumes all DRAM standards use PRE to close a row
                    // It's better to make it more general.
                    auto end = begin + int(ctrl->channel->spec->scope[int(T::Command::PRE)]) + 1;
                    vector<int> rowgroup(begin, end); // bank or subarray
                    for (const auto& hit_req_rowgroup : hit_reqs) {
                        if (rowgroup == hit_req_rowgroup) {
                            violate_hit = true;
                            break;
                        }  
                    }
                }
                if (violate_hit) {
                    continue;
                }
                // If it comes here, that means it won't violate any hit request
                if (head == q.end()) {
                    head = itr;
                } else {
                    head = compare[int(Type::FRFCFS)](head, itr);
                }
            }

            return head;
        }
    }

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x220, %rsp            # imm = 0x220
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x1e8(%rbp)
cmpl $0x3, 0x8(%rax)
je 0x4111d
movq -0x18(%rbp), %rdi
callq 0x409b0
cmpq $0x0, %rax
jne 0x41079
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0x8(%rbp)
jmp 0x41772
movq -0x18(%rbp), %rdi
callq 0x42b70
movq %rax, -0x8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x42b70
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rdi
movl $0x1, %esi
callq 0x432a0
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0x30(%rbp)
leaq -0x20(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x41790
testb $0x1, %al
jne 0x410c5
jmp 0x41118
movq -0x1e8(%rbp), %rax
movq %rax, %rdi
addq $0x18, %rdi
movslq 0x8(%rax), %rax
shlq $0x5, %rax
addq %rax, %rdi
movq -0x8(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x40(%rbp), %rsi
movq -0x48(%rbp), %rdx
callq 0x432d0
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x8(%rbp)
leaq -0x20(%rbp), %rdi
xorl %esi, %esi
callq 0x43320
movq %rax, -0x50(%rbp)
jmp 0x410a5
jmp 0x41772
movq -0x18(%rbp), %rdi
callq 0x409b0
cmpq $0x0, %rax
jne 0x4113e
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0x8(%rbp)
jmp 0x41772
movq -0x18(%rbp), %rdi
callq 0x42b70
movq %rax, -0x8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x42b70
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rdi
movl $0x1, %esi
callq 0x432a0
movq %rax, -0x58(%rbp)
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0x68(%rbp)
leaq -0x58(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x41790
testb $0x1, %al
jne 0x4118a
jmp 0x411d6
movq -0x1e8(%rbp), %rdi
addq $0x18, %rdi
addq $0x60, %rdi
movq -0x8(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x78(%rbp), %rsi
movq -0x80(%rbp), %rdx
callq 0x432d0
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x8(%rbp)
leaq -0x58(%rbp), %rdi
xorl %esi, %esi
callq 0x43320
movq %rax, -0x88(%rbp)
jmp 0x4116a
movq -0x1e8(%rbp), %rax
movq (%rax), %rdi
movq -0x8(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rsi
callq 0x2f080
testb $0x1, %al
jne 0x411fd
jmp 0x41229
movq -0x1e8(%rbp), %rax
movq (%rax), %rdi
movq -0x8(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rsi
callq 0x311e0
testb $0x1, %al
jne 0x41224
jmp 0x41229
jmp 0x41772
leaq -0xb0(%rbp), %rdi
callq 0x32cf0
movq -0x18(%rbp), %rdi
callq 0x42b70
movq %rax, -0xb8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0xc0(%rbp)
leaq -0xb8(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x41790
testb $0x1, %al
jne 0x41271
jmp 0x41409
movq -0x1e8(%rbp), %rax
movq (%rax), %rdi
movq -0xb8(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rsi
callq 0x311e0
movb %al, -0x1e9(%rbp)
jmp 0x4129d
movb -0x1e9(%rbp), %al
testb $0x1, %al
jne 0x412ac
jmp 0x413f6
leaq -0xb8(%rbp), %rdi
callq 0x2eb90
movq %rax, %rdi
addq $0x10, %rdi
callq 0x334e0
movq %rax, %rcx
movq -0x1e8(%rbp), %rax
movq %rcx, -0xe0(%rbp)
movq (%rax), %rax
movq 0x1098(%rax), %rax
movq 0x390(%rax), %rax
movslq 0x184(%rax), %rsi
leaq -0xe0(%rbp), %rdi
callq 0x43350
movq %rax, -0xf0(%rbp)
leaq -0xf0(%rbp), %rdi
movl $0x1, %esi
callq 0x43350
movq %rax, -0xe8(%rbp)
movq -0xe0(%rbp), %rax
movq %rax, -0x110(%rbp)
movq -0xe8(%rbp), %rax
movq %rax, -0x118(%rbp)
leaq -0x119(%rbp), %rdi
movq %rdi, -0x1f8(%rbp)
callq 0x2fb30
movq -0x1f8(%rbp), %rcx
movq -0x110(%rbp), %rsi
movq -0x118(%rbp), %rdx
leaq -0x108(%rbp), %rdi
callq 0x43390
jmp 0x4136a
leaq -0x119(%rbp), %rdi
callq 0x2fbd0
leaq -0xb0(%rbp), %rdi
leaq -0x108(%rbp), %rsi
callq 0x43410
jmp 0x4138b
leaq -0x108(%rbp), %rdi
callq 0x2fcd0
jmp 0x413f6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
jmp 0x41764
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x119(%rbp), %rdi
callq 0x2fbd0
jmp 0x41764
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x108(%rbp), %rdi
callq 0x2fcd0
jmp 0x41764
jmp 0x413f8
leaq -0xb8(%rbp), %rdi
callq 0x42f20
jmp 0x41245
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0x128(%rbp)
movq -0x128(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x42b70
movq %rax, -0x130(%rbp)
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0x138(%rbp)
leaq -0x130(%rbp), %rdi
leaq -0x138(%rbp), %rsi
callq 0x41790
testb $0x1, %al
jne 0x41460
jmp 0x41756
movq -0x1e8(%rbp), %rax
movb $0x0, -0x139(%rbp)
movq (%rax), %rdi
movq -0x130(%rbp), %rax
movq %rax, -0x148(%rbp)
movq -0x148(%rbp), %rsi
callq 0x311e0
movb %al, -0x1f9(%rbp)
jmp 0x41493
movb -0x1f9(%rbp), %al
testb $0x1, %al
jne 0x416a0
jmp 0x414a3
movq -0x1e8(%rbp), %rax
movq (%rax), %rdi
movq -0x130(%rbp), %rax
movq %rax, -0x150(%rbp)
movq -0x150(%rbp), %rsi
callq 0x41ba0
movb %al, -0x1fa(%rbp)
jmp 0x414cf
movb -0x1fa(%rbp), %al
testb $0x1, %al
jne 0x414de
jmp 0x416a0
leaq -0x130(%rbp), %rdi
callq 0x2eb90
movq %rax, %rdi
addq $0x10, %rdi
callq 0x334e0
movq %rax, %rcx
movq -0x1e8(%rbp), %rax
movq %rcx, -0x158(%rbp)
movq (%rax), %rax
movq 0x1098(%rax), %rax
movq 0x390(%rax), %rax
movslq 0x184(%rax), %rsi
leaq -0x158(%rbp), %rdi
callq 0x43350
movq %rax, -0x168(%rbp)
leaq -0x168(%rbp), %rdi
movl $0x1, %esi
callq 0x43350
movq %rax, -0x160(%rbp)
movq -0x158(%rbp), %rax
movq %rax, -0x188(%rbp)
movq -0x160(%rbp), %rax
movq %rax, -0x190(%rbp)
leaq -0x191(%rbp), %rdi
movq %rdi, -0x208(%rbp)
callq 0x2fb30
movq -0x208(%rbp), %rcx
movq -0x188(%rbp), %rsi
movq -0x190(%rbp), %rdx
leaq -0x180(%rbp), %rdi
callq 0x43390
jmp 0x4159c
leaq -0x191(%rbp), %rdi
callq 0x2fbd0
leaq -0xb0(%rbp), %rax
movq %rax, -0x1a0(%rbp)
movq -0x1a0(%rbp), %rdi
callq 0x43480
movq %rax, -0x1a8(%rbp)
movq -0x1a0(%rbp), %rdi
callq 0x434b0
movq %rax, -0x1b0(%rbp)
leaq -0x1a8(%rbp), %rdi
leaq -0x1b0(%rbp), %rsi
callq 0x434e0
testb $0x1, %al
jne 0x415f8
jmp 0x41694
leaq -0x1a8(%rbp), %rdi
callq 0x43520
movq %rax, -0x1b8(%rbp)
movq -0x1b8(%rbp), %rsi
leaq -0x180(%rbp), %rdi
callq 0x43540
movb %al, -0x209(%rbp)
jmp 0x41626
movb -0x209(%rbp), %al
testb $0x1, %al
jne 0x41632
jmp 0x41681
movb $0x1, -0x139(%rbp)
jmp 0x41694
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x191(%rbp), %rdi
callq 0x2fbd0
jmp 0x41764
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x180(%rbp), %rdi
callq 0x2fcd0
jmp 0x41764
jmp 0x41683
leaq -0x1a8(%rbp), %rdi
callq 0x435c0
jmp 0x415dc
leaq -0x180(%rbp), %rdi
callq 0x2fcd0
testb $0x1, -0x139(%rbp)
je 0x416ae
jmp 0x4173c
movq -0x18(%rbp), %rdi
callq 0x417c0
movq %rax, -0x1c0(%rbp)
leaq -0x8(%rbp), %rdi
leaq -0x1c0(%rbp), %rsi
callq 0x435e0
testb $0x1, %al
jne 0x416d4
jmp 0x416e1
movq -0x130(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x4173a
movq -0x1e8(%rbp), %rdi
addq $0x38, %rdi
movq -0x8(%rbp), %rax
movq %rax, -0x1d0(%rbp)
movq -0x130(%rbp), %rax
movq %rax, -0x1d8(%rbp)
movq -0x1d0(%rbp), %rsi
movq -0x1d8(%rbp), %rdx
callq 0x432d0
movq %rax, -0x218(%rbp)
jmp 0x41721
movq -0x218(%rbp), %rax
movq %rax, -0x1c8(%rbp)
movq -0x1c8(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x4173c
leaq -0x130(%rbp), %rdi
xorl %esi, %esi
callq 0x43320
movq %rax, -0x1e0(%rbp)
jmp 0x41434
leaq -0xb0(%rbp), %rdi
callq 0x32df0
jmp 0x41772
leaq -0xb0(%rbp), %rdi
callq 0x32df0
jmp 0x4177f
movq -0x8(%rbp), %rax
addq $0x220, %rsp            # imm = 0x220
popq %rbp
retq
movq -0xd0(%rbp), %rdi
callq 0xc5d0
nopl (%rax,%rax)