#ifndef _BUFFER_HXX_ #define _BUFFER_HXX_ /************************************************************************* NAME: BUFFER (buf) SYNOPSIS: A resizable object which lives in the application heap. It uses a local inlined buffer object to cache the commonly used allocation units and allows storage of INLINED_BUFFER_LEN bytes. Upon construction, the buffer takes a requested size in bytes; it allocates storage sufficient to hold that size. The client can later change this size with Resize, Trim, and FillOut. QuerySize returns the current size of the buffer; QueryPtr returns a pointer to its storage. Note that a buffer may have size 0, in which case it keeps no allocated storage. INTERFACE: BUFFER() - Constructor, naming initial size in bytes QuerySize() - return size in bytes QueryPtr() - return pointer to data buffer Resize() - resize the object to the given number of bytes. Returns TRUE if the resize was successful; otherwise returns FALSE (use GetLastError for error code) **************************************************************************/ /* I picked up the INLINED_BUFFER_LEN based on following factors 1) W3svc was using buffers of length < 16 bytes for 70% of transactions 2) A cache line is usually 32 bytes or multiples thereof and it may have subblocking of about 16/32 bytes. Choice of 16 bytes allows the BUFFER & STR objects to fit into even a conservative L1 cache line August 1999: upped from 16 to 32 */ # define INLINED_BUFFER_LEN (32) class BUFFER { private: // // Lots of code uses BUFFER class to store a bunch of different // structures, so m_rgb needs to be 8 byte aligned, so put it as the // first member // BYTE m_rgb[INLINED_BUFFER_LEN]; // the default buffer object BYTE * m_pb; // pointer to storage UINT m_cb; // size of storage, as requested by client DWORD m_fIsDynAlloced : 1; // is m_pb dynamically allocated ? DWORD m_fValid : 1; // is this object valid BOOL GetNewStorage( UINT cbRequested ); BOOL ReallocStorage( UINT cbNewlyRequested ); VOID VerifyState(VOID) const; BOOL IsDynAlloced(VOID) const { return ( m_fIsDynAlloced); } public: BUFFER( UINT cbRequested = 0 ) : m_pb (m_rgb), m_cb (INLINED_BUFFER_LEN), m_fIsDynAlloced (0), m_fValid (1) { m_rgb[0] = '\0'; if ( cbRequested > INLINED_BUFFER_LEN ) { GetNewStorage(cbRequested); } } // This constructor is used for most scratch BUFFER objects on stack // BUFFER does not free this pbInit on its own. BUFFER( BYTE * pbInit, UINT cbInit) : m_pb (pbInit), m_cb (cbInit), m_fIsDynAlloced (0), m_fValid (1) { m_pb[0] = '\0'; } ~BUFFER(void) { if ( IsDynAlloced()) { ::LocalFree( (HANDLE) m_pb ); } } VOID * QueryPtr() const { return ( (VOID * ) m_pb); } UINT QuerySize() const { return m_cb; } // // If a resize is needed, added cbSlop to it // BOOL Resize( UINT cbNewSize ) { if ( cbNewSize <= QuerySize() ) { return TRUE; } return ReallocStorage( cbNewSize ); } BOOL Resize( UINT cbNewSize, UINT cbSlop ) { if ( cbNewSize <= QuerySize() ) { return TRUE; } return ReallocStorage( cbNewSize + cbSlop ); } VOID FreeMemory( VOID ); VOID SetValid( BOOL fValid) { m_fValid = ((fValid) ? 1 : 0); } BOOL IsValid( VOID) const { return ( m_fValid); } private: BOOL ResizeAux( UINT cbNewReqestedSize, UINT cbSlop); }; // class BUFFER // // Quick macro for declaring a BUFFER that will use stack memory of // bytes. If the buffer overflows then a heap buffer will be allocated // #define STACK_BUFFER(name, size) BYTE __ach##name[size]; \ BUFFER name(__ach##name, sizeof(__ach##name)) // // NYI: This should be probably moved over to ODBC which is the only user. // BUFFER_CHAIN_ITEM is a single item in a chain of buffers // class BUFFER_CHAIN_ITEM : public BUFFER { friend class BUFFER_CHAIN; public: BUFFER_CHAIN_ITEM( UINT cbReq = 0 ) : BUFFER( cbReq ), _cbUsed( 0 ) { _ListEntry.Flink = NULL; } ~BUFFER_CHAIN_ITEM() { if ( _ListEntry.Flink ) RemoveEntryList( &_ListEntry ); } DWORD QueryUsed( VOID ) const { return _cbUsed; } VOID SetUsed( DWORD cbUsed ) { _cbUsed = cbUsed; } private: LIST_ENTRY _ListEntry; DWORD _cbUsed; // Bytes of valid data in this buffer VOID VerifyState() const; }; // class BUFFER_CHAIN_ITEM class BUFFER_CHAIN { public: BUFFER_CHAIN() { InitializeListHead( &_ListHead ); } ~BUFFER_CHAIN() { DeleteChain(); } BOOL AppendBuffer( BUFFER_CHAIN_ITEM * pBCI ); // // Returns total number of bytes freed by deleting all of the buffer // chain items // DWORD DeleteChain(); // // Enums buffer chain. Pass pBCI as NULL on first call, pass return // value till NULL on subsequent calls // BUFFER_CHAIN_ITEM * NextBuffer( BUFFER_CHAIN_ITEM * pBCI ); // // Gives back total number of bytes allocated by chain (includes unused // bytes) // DWORD CalcTotalSize( BOOL fUsed = FALSE ) const; private: LIST_ENTRY _ListHead; }; // class BUFFER_CHAIN #endif // _BUFFER_HXX_