#include "Benchmark.h"
#include "LinkedList.h"
#include "Utilities.h"
#include <algorithm>
#include <functional>
#include <new>
void __print_result_line(FILE *fp, int rep, int sz, double ms, int cmp, int mov, int mem)
{
    fprintf(fp,
            "合并两个长度为 %d 的线性表 %d 次所耗费的总时间为：%.6lf ms, 元素移动总次数： %d, 元素值比较总次数： %d, 辅助空间总字节数： %d\n",
            sz, rep, ms, cmp, mov, mem);
    fprintf(stdout, "合并两个长度为 %d 的线性表 %d 次所耗费的总时间为：%.6lf ms\n", sz, rep, ms);
}
void benchmark_hw3_2(int mn, int mx, int stp, int rep)
{
    using namespace std;
    /*
    Merge( )函数实现将两个有序单链表La和lb归并到当前操作对象*this表中，
    要求La、Lb、*this三个单链表的每个结点被访问一次，且仅被访问一次。
    */
    using TNode = LinkNode<int>;
    using TList = LinkedList<int>;
    using TPNode = TNode *;
    using TPList = TList *;
    Random rnd;
    Timer timer;
    FileHandleExitOnFail fp("benchmark_hw3_2.txt", "w");
    int *nums = new int[2ll * mx * rep];
    if (!nums) __error_then_exit("Memory alloc failed.");
    TPList lists = (TPList)malloc(sizeof(TList) * 3 * rep);
    for (int sz = mn; sz <= mx; sz += stp)
    {
        generate(nums, nums + 2 * sz * rep, [&]() { return rnd.next(0, sz); });
        Array2DView<int> nums_view(2 * sz, nums);
        for (int i = 0; i < rep; i++)
        {
            sort(nums_view[i], nums_view[i] + sz);
            sort(nums_view[i] + sz, nums_view[i + 1]);
        }
        Array2DView<TList> lists_view(3, lists);
        for (int i = 0; i < rep; i++)
        {
            new (&lists_view[i][0]) TList();
            new (&lists_view[i][1]) TList();
            new (&lists_view[i][2]) TList();
            TPNode last = nullptr;
            for (int k = sz - 1; k >= 0; k--)
            {
                TPNode nxt = new LinkNode<int>(nums_view[i][k], last);
                last = nxt;
            }
            lists_view[i][1].getHead()->link = last;
            last = nullptr;
            for (int k = sz + sz - 1; k >= sz; k--)
            {
                TPNode nxt = new LinkNode<int>(nums_view[i][k], last);
                last = nxt;
            }
            lists_view[i][2].getHead()->link = last;
        }
        timer.start();
        auto mem1 = __get_working_set_size();
        for (int i = 0; i < rep; i++)
            lists_view[i][0].Merge(lists_view[i][1], lists_view[i][2]);
        auto mem2 = __get_working_set_size();
        auto diff = mem2 - mem1;
        timer.stop();
        for (int i = 0; i < rep; i++)
            sort(nums_view[i], nums_view[i + 1]);
        for (int i = 0; i < rep; i++)
        {
            TPNode h = lists_view[i][0].getHead()->link;
            for (int j = 0; j < sz + sz; j++, h = h->link)
                if (!h || h->data != nums_view[i][j])
                    __error_then_exit("Wrong answer! Not correctly merged.");
        }
        int cmp_sum = 0, mov_sum = 0, mem_sum = 0;
        for (int i = 0; i < rep; i++)
        {
            cmp_sum += lists_view[i][0].counter.get_cmp();
            mov_sum += lists_view[i][0].counter.get_mov();
            mem_sum += lists_view[i][0].counter.get_mem();
        }
        for (int i = 0; i < rep; i++)
        {
            lists_view[i][0].~LinkedList();
            lists_view[i][1].~LinkedList();
            lists_view[i][2].~LinkedList();
        }
        __print_result_line(fp, rep, sz, timer.diff_in_ms(), cmp_sum, mov_sum, diff);
    }
    free(lists);
    delete[] nums;
}
