jbuff.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #ifndef JBUFF_HPP
  14. #define JBUFF_HPP
  15. #include "jiface.hpp"
  16. #include "jmutex.hpp"
  17. class StringAttr;
  18. class StringBuffer;
  19. class jlib_decl MemoryAttr
  20. {
  21. public:
  22. inline MemoryAttr() { len = 0; ptr = NULL; }
  23. MemoryAttr(size_t _len);
  24. MemoryAttr(size_t _len, const void * _ptr);
  25. MemoryAttr(const MemoryAttr & src);
  26. inline ~MemoryAttr() { free(ptr); }
  27. void * allocate(size_t _len);
  28. void clear();
  29. void * detach();
  30. void * ensure(size_t _len);
  31. void * reallocate(size_t _len);
  32. inline const void * get() const { return ptr; }
  33. inline size_t length() const { return len; }
  34. inline void * mem() const { return ptr; }
  35. void set(size_t _len, const void * _ptr);
  36. void setOwn(size_t _len, void * _ptr);
  37. static int compare(const MemoryAttr & m1, const MemoryAttr & m2);
  38. inline void * bufferBase() const { return ptr; } // like get except non-const
  39. private:
  40. void * ptr;
  41. size_t len;
  42. };
  43. //--------------------------------------------------------------------------------------------------------------------
  44. interface IMemoryBlock
  45. {
  46. public:
  47. virtual const byte * get() const = 0;
  48. virtual byte * getMem() const = 0;
  49. virtual byte * ensure(size32_t len) = 0;
  50. };
  51. class jlib_decl CMemoryBlock : public IMemoryBlock
  52. {
  53. public:
  54. virtual const byte * get() const
  55. {
  56. return reinterpret_cast<const byte *>(memory.get());
  57. }
  58. virtual byte * getMem() const
  59. {
  60. return reinterpret_cast<byte *>(memory.mem());
  61. }
  62. virtual byte * ensure(size32_t len)
  63. {
  64. return reinterpret_cast<byte *>(memory.ensure(len));
  65. }
  66. protected:
  67. MemoryAttr memory;
  68. };
  69. //--------------------------------------------------------------------------------------------------------------------
  70. template <class CLASS> class OwnedMalloc
  71. {
  72. public:
  73. inline OwnedMalloc() { ptr = NULL; }
  74. inline OwnedMalloc(CLASS * _ptr) { ptr = _ptr; }
  75. explicit inline OwnedMalloc(unsigned n, bool clearMemory = false) { doAllocate(n, clearMemory); }
  76. inline ~OwnedMalloc() { free(ptr); }
  77. inline CLASS * operator -> () const { return ptr; }
  78. inline operator CLASS *() const { return ptr; }
  79. inline void clear() { CLASS *temp=ptr; ptr=NULL; free(temp); }
  80. inline CLASS * get() const { return ptr; }
  81. inline CLASS * getClear() { CLASS * temp = ptr; ptr = NULL; return temp; }
  82. inline void setown(CLASS * _ptr) { CLASS * temp = ptr; ptr = _ptr; free(temp); }
  83. inline void allocate(bool clearMemory = false) { allocateN(1, clearMemory); }
  84. inline void allocateN(unsigned n, bool clearMemory = false)
  85. {
  86. clear();
  87. doAllocate(n, clearMemory);
  88. }
  89. private:
  90. inline OwnedMalloc(const OwnedMalloc<CLASS> & other);
  91. inline void doAllocate(unsigned n, bool clearMemory = false)
  92. {
  93. void * mem = clearMemory ? calloc(n, sizeof(CLASS)) : malloc(n * sizeof(CLASS));
  94. ptr = static_cast<CLASS *>(mem);
  95. }
  96. void allocate(unsigned n, bool clearMemory = false);
  97. void operator = (CLASS * _ptr);
  98. void operator = (const OwnedMalloc<CLASS> & other);
  99. void set(CLASS * _ptr);
  100. void set(const OwnedMalloc<CLASS> &other);
  101. void setown(const OwnedMalloc<CLASS> &other);
  102. private:
  103. CLASS * ptr;
  104. };
  105. #define MEMBUFFER_MAXLEN UINT_MAX // size32_t
  106. class jlib_decl MemoryBuffer
  107. {
  108. public:
  109. inline MemoryBuffer() { init(); }
  110. MemoryBuffer(size_t initial);
  111. MemoryBuffer(size_t len, const void * buffer);
  112. inline ~MemoryBuffer() { kill(); }
  113. MemoryBuffer & rewrite(size32_t pos = 0);
  114. MemoryBuffer & append(char value);
  115. MemoryBuffer & append(unsigned char value);
  116. MemoryBuffer & append(bool value);
  117. MemoryBuffer & append(const char * value);
  118. MemoryBuffer & append(const unsigned char * value);
  119. MemoryBuffer & append(size32_t len, const void * value);
  120. MemoryBuffer & append(double value);
  121. MemoryBuffer & append(float value);
  122. MemoryBuffer & append(short value);
  123. MemoryBuffer & append(unsigned short value);
  124. MemoryBuffer & append(int value);
  125. MemoryBuffer & append(unsigned value);
  126. MemoryBuffer & append(__int64 value);
  127. MemoryBuffer & append(unsigned __int64 value);
  128. MemoryBuffer & append(const MemoryBuffer & value);
  129. MemoryBuffer & appendBytes(unsigned char value, unsigned count);
  130. MemoryBuffer & appendEndian(size32_t len, const void * value);
  131. MemoryBuffer & appendFile(const char *fileName);
  132. MemoryBuffer & appendSwap(size32_t len, const void * value);
  133. MemoryBuffer & appendPacked(unsigned __int64 value); // compatible with any unsigned size
  134. inline MemoryBuffer & appendMemSize(memsize_t value) { __int64 val=(__int64)value; append(val); return *this; }
  135. MemoryBuffer & reset(size32_t pos = 0);
  136. MemoryBuffer & read(char & value);
  137. MemoryBuffer & read(unsigned char & value);
  138. MemoryBuffer & read(bool & value);
  139. MemoryBuffer & read(StringAttr & value);
  140. MemoryBuffer & read(StringBuffer & value);
  141. MemoryBuffer & read(const char * & value);
  142. MemoryBuffer & read(size32_t len, void * value);
  143. MemoryBuffer & read(double & value);
  144. MemoryBuffer & read(float & value);
  145. MemoryBuffer & read(short & value);
  146. MemoryBuffer & read(unsigned short & value);
  147. MemoryBuffer & read(int & value);
  148. MemoryBuffer & read(unsigned & value);
  149. MemoryBuffer & read(__int64 & value);
  150. MemoryBuffer & read(unsigned __int64 & value);
  151. MemoryBuffer & readEndian(size32_t len, void * value);
  152. MemoryBuffer & readFile(StringAttr &fileName);
  153. MemoryBuffer & readSwap(size32_t len, void * value);
  154. const byte * readDirect(size32_t len); // for efficiency
  155. MemoryBuffer & readPacked(unsigned & value);
  156. MemoryBuffer & readPacked(unsigned __int64 & value);
  157. inline MemoryBuffer & readMemSize(memsize_t & value) { __int64 val; read(val); value = (memsize_t)val; assertex(val == (__int64) value); return *this; }
  158. MemoryBuffer & skip(unsigned len);
  159. void writeDirect(size32_t pos,size32_t len,const void *buf); // NB does not extend buffer
  160. void writeEndianDirect(size32_t pos,size32_t len,const void *buf); // NB does not extend buffer
  161. inline size32_t getPos() { return readPos; }; // read ptr
  162. inline MemoryBuffer & clear() { curLen = 0; readPos = 0; return *this; }
  163. inline bool needSwapEndian() { return swapEndian; }
  164. int setEndian(int endian); // pass __[BIG|LITTLE]_ENDIAN
  165. bool setSwapEndian(bool swap);
  166. inline const char * toByteArray() const { return curLen ? buffer : NULL; }
  167. void swapWith(MemoryBuffer & other);
  168. inline size32_t capacity() { return (maxLen - curLen); }
  169. void * ensureCapacity (unsigned max);
  170. inline size32_t length() const { return curLen; }
  171. inline size32_t remaining() const { return curLen - readPos; }
  172. void resetBuffer();
  173. void setBuffer(size_t len, void * buffer, bool takeOwnership=false);
  174. void setLength(unsigned len);
  175. void setWritePos(unsigned len); // only use for back patching data
  176. void * detach();
  177. void * detachOwn(); // Never reallocates
  178. //Non-standard functions:
  179. void * reserve(unsigned size);
  180. void truncate(); // truncates (i.e. minimizes allocation) to current size
  181. void * reserveTruncate(unsigned size); // reserves and truncates to that size
  182. void * insertDirect(unsigned offset, size32_t len); // insert len bytes at offset returning address to area inserted
  183. inline void Release() const { delete this; } // for consistency even though not link counted
  184. inline void * bufferBase() const { return buffer; }
  185. protected:
  186. size32_t readPos;
  187. bool swapEndian;
  188. private:
  189. MemoryBuffer & read(unsigned long & value); // unimplemented
  190. MemoryBuffer & read(long & value); // unimplemented
  191. MemoryBuffer & append(long value); // unimplemented
  192. MemoryBuffer & append(unsigned long value); // unimplemented
  193. void _insert(unsigned offset, size32_t len);
  194. void init();
  195. void kill();
  196. unsigned __int64 readPacked();
  197. void _realloc(size32_t max);
  198. void _reallocExact(size32_t max);
  199. MemoryBuffer & _remove(unsigned start, unsigned len);
  200. MemoryBuffer & _reverse();
  201. const char* _str();
  202. mutable char * buffer;
  203. size32_t curLen;
  204. size32_t maxLen;
  205. bool ownBuffer;
  206. MemoryBuffer(MemoryBuffer & value);
  207. };
  208. // Utility class, to back patch a scalar into current position
  209. template <class CLASS>
  210. class DelayedMarker
  211. {
  212. protected:
  213. MemoryBuffer &mb;
  214. size32_t pos;
  215. public:
  216. DelayedMarker(MemoryBuffer &_mb) : mb(_mb)
  217. {
  218. restart();
  219. }
  220. inline void write(CLASS a)
  221. {
  222. mb.writeEndianDirect(pos, sizeof(a), &a);
  223. }
  224. // resets position marker and writes CLASS # bytes to be filled subsequently by write()
  225. inline void restart()
  226. {
  227. pos = mb.length();
  228. mb.appendBytes(0, sizeof(CLASS));
  229. }
  230. };
  231. // Utility class, to back patch a size into current position
  232. class DelayedSizeMarker : private DelayedMarker<size32_t>
  233. {
  234. typedef DelayedMarker<size32_t> PARENT;
  235. public:
  236. DelayedSizeMarker(MemoryBuffer &mb) : PARENT(mb)
  237. {
  238. }
  239. inline void write()
  240. {
  241. size32_t sz = size();
  242. PARENT::write(sz);
  243. }
  244. inline size32_t size() const
  245. {
  246. return (size32_t)(mb.length() - (pos + sizeof(size32_t)));
  247. }
  248. inline void restart() { PARENT::restart(); }
  249. };
  250. interface jlib_decl serializable : extends IInterface
  251. {
  252. public:
  253. virtual void serialize(MemoryBuffer &tgt) = 0;
  254. virtual void deserialize(MemoryBuffer &src) = 0;
  255. };
  256. class jlib_decl MemoryBuffer2IDataVal : implements IDataVal
  257. {
  258. public:
  259. MemoryBuffer2IDataVal(MemoryBuffer & _buffer) : buffer(_buffer) {}
  260. virtual const void * data() const { return buffer.toByteArray(); }
  261. virtual void clear() { } // clearing when appending does nothing
  262. virtual void setLen(const void * val, size_t length) { buffer.append((size32_t)length, val); }
  263. virtual size_t length() const { return buffer.length(); }
  264. virtual void * reserve(size_t length) { return buffer.reserveTruncate((size32_t)length); }
  265. private:
  266. MemoryBuffer & buffer;
  267. };
  268. class jlib_decl MemoryAttr2IStringVal : implements IStringVal
  269. {
  270. public:
  271. MemoryAttr2IStringVal(MemoryAttr & _attr) : attr(_attr) {}
  272. virtual const char * str() const;
  273. virtual void set(const char *val) { attr.set(strlen(val), val); }
  274. virtual void clear() { attr.clear(); } // clearing when appending does nothing
  275. virtual void setLen(const char *val, unsigned length) { attr.set(length, val); }
  276. virtual unsigned length() const { return (size32_t)attr.length(); };
  277. protected:
  278. MemoryAttr & attr;
  279. };
  280. class jlib_decl Variable2IDataVal : implements IDataVal
  281. {
  282. public:
  283. Variable2IDataVal(unsigned * _pLen, void * * _pData) { pLen = _pLen; pData = _pData; }
  284. virtual const void * data() const { return *pData; };
  285. virtual void clear() { free(*pData); *pData = NULL; *pLen = 0; };
  286. virtual void setLen(const void * val, size_t length) { free(*pData); *pData = malloc(length); memcpy(*pData, val, length); *pLen = (size32_t)length; }
  287. virtual size_t length() const { return *pLen; };
  288. virtual void * reserve(size_t length) { free(*pData); *pData = malloc(length); *pLen = (size32_t)length; return *pData; }
  289. private:
  290. unsigned * pLen; // Should really be a size_t
  291. void * * pData;
  292. };
  293. //Similar to above, but only used for fixed sized returns (or variable size rows with a known max length)
  294. class jlib_decl Fixed2IDataVal : implements IDataVal
  295. {
  296. public:
  297. Fixed2IDataVal(size_t _len, void * _ptr) { len = _len; ptr = _ptr; }
  298. virtual const void * data() const { return ptr; };
  299. virtual void clear() { memset(ptr, 0, len); };
  300. virtual void setLen(const void * val, size_t length) { assertex(length <= len); memcpy(ptr, val, length); }
  301. virtual size_t length() const { return len; };
  302. virtual void * reserve(size_t length) { assertex(length <= len); return ptr; }
  303. private:
  304. size_t len;
  305. void * ptr;
  306. };
  307. #ifdef __GNUC__
  308. class jlib_decl GccMemoryBuffer2IDataVal
  309. {
  310. public:
  311. GccMemoryBuffer2IDataVal(MemoryBuffer & _buffer) : adaptor(_buffer) {}
  312. inline operator IDataVal & () { return adaptor; }
  313. private:
  314. MemoryBuffer2IDataVal adaptor;
  315. };
  316. class jlib_decl GccVariable2IDataVal
  317. {
  318. public:
  319. GccVariable2IDataVal(unsigned * _pLen, void * * _pData) : adaptor(_pLen, _pData) {}
  320. inline operator IDataVal & () { return adaptor; }
  321. private:
  322. Variable2IDataVal adaptor;
  323. };
  324. #define MemoryBuffer2IDataVal GccMemoryBuffer2IDataVal
  325. #define Variable2IDataVal GccVariable2IDataVal
  326. #endif
  327. extern jlib_decl MemoryBuffer & serialize(MemoryBuffer & buffer, const MemoryAttr & value);
  328. extern jlib_decl MemoryBuffer & deserialize(MemoryBuffer & buffer, MemoryAttr & value);
  329. extern jlib_decl MemoryBuffer & serialize(MemoryBuffer & buffer, const char * value);
  330. extern jlib_decl MemoryBuffer & deserialize(MemoryBuffer & buffer, StringAttr & value);
  331. class jlib_decl CLargeMemoryAllocator
  332. {
  333. protected:
  334. struct Chunk
  335. {
  336. Chunk *prev;
  337. byte *base;
  338. size32_t max;
  339. size32_t size;
  340. } chunk;
  341. memsize_t totalmax;
  342. size32_t chunkmin;
  343. memsize_t amax; // total of max values
  344. memsize_t atot; // total allocated not including chunk.size
  345. bool throwexception;
  346. bool newchunk(size32_t sz,size32_t extra,bool exceptionwanted);
  347. virtual void allocchunkmem();
  348. virtual void disposechunkmem();
  349. public:
  350. CLargeMemoryAllocator(memsize_t _totalmax,size32_t _chunkmin,bool _throwexception)
  351. {
  352. init(_totalmax,_chunkmin,_throwexception);
  353. }
  354. CLargeMemoryAllocator();
  355. void init(memsize_t _totalmax,size32_t _chunkmin,bool _throwexception);
  356. virtual ~CLargeMemoryAllocator()
  357. {
  358. reset();
  359. }
  360. inline void setTotalMax(memsize_t total)
  361. {
  362. totalmax = total;
  363. }
  364. inline memsize_t getTotalMax()
  365. {
  366. return totalmax;
  367. }
  368. inline byte *alloc(size32_t sz,size32_t extra=0)
  369. {
  370. size32_t chsize = chunk.size;
  371. if (chsize+sz>chunk.max) {
  372. if (!newchunk(sz,extra,throwexception))
  373. return NULL;
  374. chsize = chunk.size;
  375. }
  376. byte *ret = chunk.base+chsize;
  377. chunk.size = chsize+sz;
  378. return ret;
  379. }
  380. inline bool checkAvail(size32_t sz, size32_t sza=0,size32_t extra=0)
  381. {
  382. if (chunk.size+sz>chunk.max) {
  383. if (sza<sz)
  384. sza = sz;
  385. if (!newchunk(sza,extra,false))
  386. return false;
  387. }
  388. return true;
  389. }
  390. inline memsize_t allocated()
  391. {
  392. return chunk.size+atot;
  393. }
  394. inline memsize_t maxallocated()
  395. {
  396. return amax;
  397. }
  398. void setChunkGranularity(size32_t sz)
  399. {
  400. if (sz&&(chunkmin>sz))
  401. chunkmin -= (chunkmin%sz);
  402. }
  403. void reset();
  404. void setSize(memsize_t pos);
  405. void reduceSize(memsize_t amount);
  406. byte *next(memsize_t pos,size32_t &size); // this should not be used for small jumps as it is slow
  407. MemoryBuffer &serialize(MemoryBuffer &mb);
  408. MemoryBuffer &deserialize(MemoryBuffer &mb,size32_t sz, size32_t extra=0);
  409. void *nextBuffer(void *prev,size32_t &sz); // to enumerate buffers (NULL returns first)
  410. };
  411. class CLargeMemorySequentialReader
  412. {
  413. size32_t left;
  414. memsize_t pos;
  415. const void *ptr;
  416. CLargeMemoryAllocator &allocator;
  417. inline CLargeMemorySequentialReader(CLargeMemoryAllocator &_allocator)
  418. : allocator(_allocator)
  419. {
  420. left = 0;
  421. pos = 0;
  422. }
  423. inline const void *read(size32_t &max)
  424. {
  425. if (!left) {
  426. ptr = allocator.next(pos,left);
  427. if (!left)
  428. return NULL;
  429. }
  430. max = left;
  431. return ptr;
  432. }
  433. inline void skip(size32_t sz)
  434. {
  435. assertex(left>=sz);
  436. left -= sz;
  437. pos += sz;
  438. ptr = (const byte *)ptr+sz;
  439. }
  440. };
  441. interface IOutOfMemException;
  442. jlib_decl IOutOfMemException *createOutOfMemException(int errcode, size_t wanted, size_t got=0, bool expected=false, const char *errMsg=nullptr);
  443. jlib_decl void RaiseOutOfMemException(int errcode, size_t wanted, size_t got=0, bool expected=false, const char *errMsg=nullptr);
  444. interface ILargeMemLimitNotify: extends IInterface
  445. {
  446. virtual bool take(memsize_t tot)=0; // called when a memory request about to be satisfied will exceed limit
  447. // will raise oom exception if false returned
  448. virtual void give(memsize_t tot)=0; // called when the memory allocated falls back below the limit
  449. };
  450. extern jlib_decl void setLargeMemLimitNotify(memsize_t size,ILargeMemLimitNotify *notify);
  451. inline void *checked_malloc(size_t len,int errcode)
  452. {
  453. if (len==0)
  454. return NULL;
  455. void *ret = malloc(len);
  456. if (!ret)
  457. RaiseOutOfMemException(errcode, len);
  458. return ret;
  459. }
  460. jlib_decl void *checked_realloc(void *orig, size_t newlen, size_t origlen,int errcode);
  461. class NonReentrantSpinLock;
  462. class jlib_decl CFixedSizeAllocator
  463. {
  464. private:
  465. void *freelist;
  466. void *chunklist;
  467. NonReentrantSpinLock lock;
  468. unsigned numalloc;
  469. unsigned numfree;
  470. size32_t allocsize;
  471. size32_t chunksize;
  472. void *allocChunk();
  473. void freeChunk(void *);
  474. public:
  475. CFixedSizeAllocator();
  476. CFixedSizeAllocator(size32_t _allocsize,size32_t _chunksize=0x100000);
  477. virtual ~CFixedSizeAllocator();
  478. void init(size32_t _allocsize,size32_t _chunksize=0x100000);
  479. void kill();
  480. void *alloc();
  481. void dealloc(void *blk);
  482. void stats(size32_t &sizealloc, size32_t &sizeunused);
  483. };
  484. #endif