// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_wroot_free_seg #define tools_wroot_free_seg #include "seek" #include "wbuf" #include "../forit" #include namespace tools { namespace wroot { class free_seg { public: free_seg(std::ostream& a_out,seek a_first,seek a_last) :m_out(a_out),m_first(a_first),m_last(a_last){} virtual ~free_seg(){} public: free_seg(const free_seg& a_from) :m_out(a_from.m_out),m_first(a_from.m_first),m_last(a_from.m_last) {} free_seg& operator=(const free_seg& a_from){ m_first = a_from.m_first; m_last = a_from.m_last; return *this; } public: std::ostream& out() const {return m_out;} seek first() const {return m_first;} seek last() const {return m_last;} void set_first(seek a_v) {m_first = a_v;} void set_last(seek a_v) {m_last = a_v;} unsigned int record_size() const { if((m_first>START_BIG_FILE())|| //GB (m_last>START_BIG_FILE()) ){ return sizeof(short) + 2 * sizeof(seek); } else { return sizeof(short) + 2 * sizeof(seek32); } } bool fill_buffer(wbuf& a_wb) { short version = 1; if((m_first>START_BIG_FILE())|| (m_last>START_BIG_FILE())) version += big_file_version_tag(); if(!a_wb.write(version)) return false; if(version>(short)big_file_version_tag()) { if(!a_wb.write(m_first)) return false; if(!a_wb.write(m_last)) return false; } else { if(m_first>START_BIG_FILE()) { //GB m_out << "tools::wroot::free_seg::fill_buffer :" << " attempt to write big Seek " << m_first << " on 32 bits." << std::endl; return false; } if(!a_wb.write((seek32)m_first)) return false; if(m_last>START_BIG_FILE()) { //GB m_out << "tools::wroot::free_seg::fill_buffer :" << " attempt to write big seek " << m_last << " on 32 bits." << std::endl; return false; } if(!a_wb.write((seek32)m_last)) return false; } return true; } protected: std::ostream& m_out; seek m_first; //First free word of segment seek m_last; //Last free word of segment }; }} #include namespace tools { namespace wroot { inline free_seg* find_after(const std::list& a_list,free_seg* a_what) { tools_lforcit(free_seg*,a_list,it) { if((*it)==a_what) { it++; if(it==a_list.end()) return 0; return *it; } } return 0; } inline void remove(std::list& a_list,free_seg* a_what) { //NOTE : it does not delete a_what. tools_lforit(free_seg*,a_list,it) { if((*it)==a_what) { a_list.erase(it); return; } } } inline void add_before(std::list& a_list,free_seg* a_what,free_seg* a_new) { tools_lforit(free_seg*,a_list,it) { if((*it)==a_what) { a_list.insert(it,a_new); return; } } } inline free_seg* add_free(std::list& a_list,seek a_first,seek a_last) { // Add a new free segment to the list of free segments // =================================================== // If last just preceedes an existing free segment, then first becomes // the new starting location of the free segment. // if first just follows an existing free segment, then last becomes // the new ending location of the free segment. // if first just follows an existing free segment AND last just preceedes // an existing free segment, these two segments are merged into // one single segment. // free_seg* idcur = a_list.front(); while (idcur) { seek curfirst = idcur->first(); seek curlast = idcur->last(); if (curlast == (a_first-1)) { idcur->set_last(a_last); free_seg* idnext = find_after(a_list,idcur); if (idnext == 0) return idcur; if (idnext->first() > (a_last+1)) return idcur; idcur->set_last(idnext->last()); remove(a_list,idnext); //idnext not deleted. delete idnext; return idcur; } if (curfirst == (a_last+1)) { idcur->set_first(a_first); return idcur; } if (a_first < curfirst) { free_seg* newfree = new free_seg(idcur->out(),a_first,a_last); add_before(a_list,idcur,newfree); return newfree; } idcur = find_after(a_list,idcur); } return 0; } }} #endif