// This file is part of the ustl library, an STL implementation. // // Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> // This file is free software, distributed under the MIT License. // // memblock.cc // // Allocated memory block. // #include "fstream.h" #include "mistream.h" #include "memblock.h" #include "ualgo.h" #include "uassert.h" #include "umemory.h" #include <errno.h> namespace ustl { /// Allocates 0 bytes for the internal block. memblock::memblock (void) : memlink (), m_Capacity (0) { } /// Allocates \p n bytes for the internal block. memblock::memblock (size_type n) : memlink (), m_Capacity (0) { resize (n); } /// links to \p p, \p n. Data can not be modified and will not be freed. memblock::memblock (const void* p, size_type n) : memlink (), m_Capacity (0) { assign (p, n); } /// Links to what \p b is linked to. memblock::memblock (const cmemlink& b) : memlink (), m_Capacity (0) { assign (b); } /// Links to what \p b is linked to. memblock::memblock (const memlink& b) : memlink (), m_Capacity (0) { assign (b); } /// Links to what \p b is linked to. memblock::memblock (const memblock& b) : memlink (), m_Capacity (0) { assign (b); } /// Frees internal data, if appropriate /// Only if the block was allocated using resize, or linked to using Manage, /// will it be freed. Also, Derived classes should call DestructBlock from /// their destructor, because upstream virtual functions are unavailable at /// this point and will not be called automatically. /// memblock::~memblock (void) { if (!is_linked()) deallocate(); } /// resizes the block to \p newSize bytes, reallocating if necessary. void memblock::resize (size_type newSize, bool bExact) { if (m_Capacity < newSize + minimumFreeCapacity()) reserve (newSize, bExact); memlink::resize (newSize); } /// Frees internal data. void memblock::deallocate (void) throw() { if (m_Capacity) { assert (cdata() && "Internal error: space allocated, but the pointer is NULL"); assert (data() && "Internal error: read-only block is marked as allocated space"); free (data()); } unlink(); } /// Assumes control of the memory block \p p of size \p n. /// The block assigned using this function will be freed in the destructor. void memblock::manage (void* p, size_type n) { assert (p || !n); assert (!m_Capacity && "Already managing something. deallocate or unlink first."); link (p, n); m_Capacity = n; } /// "Instantiate" a linked block by allocating and copying the linked data. void memblock::copy_link (void) { const cmemlink l (*this); if (is_linked()) unlink(); assign (l); } /// Copies data from \p p, \p n. void memblock::assign (const void* p, size_type n) { assert ((p != (const void*) cdata() || size() == n) && "Self-assignment can not resize"); resize (n); copy (p, n); } /// \brief Reallocates internal block to hold at least \p newSize bytes. /// /// Additional memory may be allocated, but for efficiency it is a very /// good idea to call reserve before doing byte-by-byte edit operations. /// The block size as returned by size() is not altered. reserve will not /// reduce allocated memory. If you think you are wasting space, call /// deallocate and start over. To avoid wasting space, use the block for /// only one purpose, and try to get that purpose to use similar amounts /// of memory on each iteration. /// void memblock::reserve (size_type newSize, bool bExact) { if ((newSize += minimumFreeCapacity()) <= m_Capacity) return; void* oldBlock (is_linked() ? NULL : data()); if (!bExact) newSize = Align (newSize, c_PageSize); pointer newBlock = (pointer) realloc (oldBlock, newSize); if (!newBlock) #if PLATFORM_ANDROID printf("bad_alloc\n"); #else throw bad_alloc (newSize); #endif if (!oldBlock && cdata()) copy_n (cdata(), min (size() + 1, newSize), newBlock); link (newBlock, size()); m_Capacity = newSize; } /// Swaps the contents with \p l void memblock::swap (memblock& l) { memlink::swap (l); ::ustl::swap (m_Capacity, l.m_Capacity); } /// Shifts the data in the linked block from \p start to \p start + \p n. memblock::iterator memblock::insert (iterator start, size_type n) { const uoff_t ip = start - begin(); assert (ip <= size()); resize (size() + n, false); memlink::insert (iat(ip), n); return (iat (ip)); } /// Shifts the data in the linked block from \p start + \p n to \p start. memblock::iterator memblock::erase (iterator start, size_type n) { const uoff_t ep = start - begin(); assert (ep + n <= size()); memlink::erase (start, n); memlink::resize (size() - n); return (iat (ep)); } /// Unlinks object. void memblock::unlink (void) { memlink::unlink(); m_Capacity = 0; } /// Reads the object from stream \p s void memblock::read (istream& is) { written_size_type n; is >> n; is.verify_remaining ("read", "ustl::memblock", n); resize (n); is.read (data(), writable_size()); is.align (alignof (n)); } /// Reads the entire file \p "filename". void memblock::read_file (const char* filename) { fstream f; f.exceptions (fstream::allbadbits); f.open (filename, fstream::in); const off_t fsize (f.size()); reserve (fsize); f.read (data(), fsize); f.close(); resize (fsize); } } // namespace ustl