Home | History | Annotate | Download | only in ustl-1.0
      1 // This file is part of the ustl library, an STL implementation.
      2 //
      3 // Copyright (C) 2005 by Mike Sharov <msharov (at) users.sourceforge.net>
      4 // This file is free software, distributed under the MIT License.
      5 //
      6 // memblock.cc
      7 //
      8 //	Allocated memory block.
      9 //
     10 
     11 #include "fstream.h"
     12 #include "mistream.h"
     13 #include "memblock.h"
     14 #include "ualgo.h"
     15 #include "uassert.h"
     16 #include "umemory.h"
     17 
     18 #include <errno.h>
     19 
     20 namespace ustl {
     21 
     22 /// Allocates 0 bytes for the internal block.
     23 memblock::memblock (void)
     24 : memlink (),
     25   m_Capacity (0)
     26 {
     27 }
     28 
     29 /// Allocates \p n bytes for the internal block.
     30 memblock::memblock (size_type n)
     31 : memlink (),
     32   m_Capacity (0)
     33 {
     34     resize (n);
     35 }
     36 
     37 /// links to \p p, \p n. Data can not be modified and will not be freed.
     38 memblock::memblock (const void* p, size_type n)
     39 : memlink (),
     40   m_Capacity (0)
     41 {
     42     assign (p, n);
     43 }
     44 
     45 /// Links to what \p b is linked to.
     46 memblock::memblock (const cmemlink& b)
     47 : memlink (),
     48   m_Capacity (0)
     49 {
     50     assign (b);
     51 }
     52 
     53 /// Links to what \p b is linked to.
     54 memblock::memblock (const memlink& b)
     55 : memlink (),
     56   m_Capacity (0)
     57 {
     58     assign (b);
     59 }
     60 
     61 /// Links to what \p b is linked to.
     62 memblock::memblock (const memblock& b)
     63 : memlink (),
     64   m_Capacity (0)
     65 {
     66     assign (b);
     67 }
     68 
     69 /// Frees internal data, if appropriate
     70 /// Only if the block was allocated using resize, or linked to using Manage,
     71 /// will it be freed. Also, Derived classes should call DestructBlock from
     72 /// their destructor, because upstream virtual functions are unavailable at
     73 /// this point and will not be called automatically.
     74 ///
     75 memblock::~memblock (void)
     76 {
     77     if (!is_linked())
     78 	deallocate();
     79 }
     80 
     81 /// resizes the block to \p newSize bytes, reallocating if necessary.
     82 void memblock::resize (size_type newSize, bool bExact)
     83 {
     84     if (m_Capacity < newSize + minimumFreeCapacity())
     85 	reserve (newSize, bExact);
     86     memlink::resize (newSize);
     87 }
     88 
     89 /// Frees internal data.
     90 void memblock::deallocate (void) throw()
     91 {
     92     if (m_Capacity) {
     93 	assert (cdata() && "Internal error: space allocated, but the pointer is NULL");
     94 	assert (data() && "Internal error: read-only block is marked as allocated space");
     95 	free (data());
     96     }
     97     unlink();
     98 }
     99 
    100 /// Assumes control of the memory block \p p of size \p n.
    101 /// The block assigned using this function will be freed in the destructor.
    102 void memblock::manage (void* p, size_type n)
    103 {
    104     assert (p || !n);
    105     assert (!m_Capacity && "Already managing something. deallocate or unlink first.");
    106     link (p, n);
    107     m_Capacity = n;
    108 }
    109 
    110 /// "Instantiate" a linked block by allocating and copying the linked data.
    111 void memblock::copy_link (void)
    112 {
    113     const cmemlink l (*this);
    114     if (is_linked())
    115 	unlink();
    116     assign (l);
    117 }
    118 
    119 /// Copies data from \p p, \p n.
    120 void memblock::assign (const void* p, size_type n)
    121 {
    122     assert ((p != (const void*) cdata() || size() == n) && "Self-assignment can not resize");
    123     resize (n);
    124     copy (p, n);
    125 }
    126 
    127 /// \brief Reallocates internal block to hold at least \p newSize bytes.
    128 ///
    129 /// Additional memory may be allocated, but for efficiency it is a very
    130 /// good idea to call reserve before doing byte-by-byte edit operations.
    131 /// The block size as returned by size() is not altered. reserve will not
    132 /// reduce allocated memory. If you think you are wasting space, call
    133 /// deallocate and start over. To avoid wasting space, use the block for
    134 /// only one purpose, and try to get that purpose to use similar amounts
    135 /// of memory on each iteration.
    136 ///
    137 void memblock::reserve (size_type newSize, bool bExact)
    138 {
    139     if ((newSize += minimumFreeCapacity()) <= m_Capacity)
    140 	return;
    141     void* oldBlock (is_linked() ? NULL : data());
    142     if (!bExact)
    143 	newSize = Align (newSize, c_PageSize);
    144     pointer newBlock = (pointer) realloc (oldBlock, newSize);
    145     if (!newBlock)
    146 #if PLATFORM_ANDROID
    147         printf("bad_alloc\n");
    148 #else
    149 	throw bad_alloc (newSize);
    150 #endif
    151     if (!oldBlock && cdata())
    152 	copy_n (cdata(), min (size() + 1, newSize), newBlock);
    153     link (newBlock, size());
    154     m_Capacity = newSize;
    155 }
    156 
    157 /// Swaps the contents with \p l
    158 void memblock::swap (memblock& l)
    159 {
    160     memlink::swap (l);
    161     ::ustl::swap (m_Capacity, l.m_Capacity);
    162 }
    163 
    164 /// Shifts the data in the linked block from \p start to \p start + \p n.
    165 memblock::iterator memblock::insert (iterator start, size_type n)
    166 {
    167     const uoff_t ip = start - begin();
    168     assert (ip <= size());
    169     resize (size() + n, false);
    170     memlink::insert (iat(ip), n);
    171     return (iat (ip));
    172 }
    173 
    174 /// Shifts the data in the linked block from \p start + \p n to \p start.
    175 memblock::iterator memblock::erase (iterator start, size_type n)
    176 {
    177     const uoff_t ep = start - begin();
    178     assert (ep + n <= size());
    179     memlink::erase (start, n);
    180     memlink::resize (size() - n);
    181     return (iat (ep));
    182 }
    183 
    184 /// Unlinks object.
    185 void memblock::unlink (void)
    186 {
    187     memlink::unlink();
    188     m_Capacity = 0;
    189 }
    190 
    191 /// Reads the object from stream \p s
    192 void memblock::read (istream& is)
    193 {
    194     written_size_type n;
    195     is >> n;
    196     is.verify_remaining ("read", "ustl::memblock", n);
    197     resize (n);
    198     is.read (data(), writable_size());
    199     is.align (alignof (n));
    200 }
    201 
    202 /// Reads the entire file \p "filename".
    203 void memblock::read_file (const char* filename)
    204 {
    205     fstream f;
    206     f.exceptions (fstream::allbadbits);
    207     f.open (filename, fstream::in);
    208     const off_t fsize (f.size());
    209     reserve (fsize);
    210     f.read (data(), fsize);
    211     f.close();
    212     resize (fsize);
    213 }
    214 
    215 } // namespace ustl
    216 
    217