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