/*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
#define SQUID_SBUF_H
#include "base/InstanceId.h"
+#include "base/TextException.h"
#include "Debug.h"
#include "globals.h"
+#include "sbuf/forward.h"
#include "sbuf/MemBlob.h"
#include "sbuf/Stats.h"
-#include "SBufExceptions.h"
#include <climits>
-#include <cstdarg>
#include <iosfwd>
#include <iterator>
#if HAVE_UNISTD_H
} SBufCaseSensitive;
class CharacterSet;
-class SBuf;
/** Forward input const_iterator for SBufs
*
protected:
SBufIterator(const SBuf &, size_type);
- const char *iter;
+ const char *iter = nullptr;
};
/** Reverse input const_iterator for SBufs
/// create an empty (zero-size) SBuf
SBuf();
SBuf(const SBuf &S);
-#if __cplusplus >= 201103L
SBuf(SBuf&& S) : store_(std::move(S.store_)), off_(S.off_), len_(S.len_) {
++stats.moves;
- S.store_=NULL; //RefCount supports NULL, and S is about to be destructed
- S.off_=0;
- S.len_=0;
+ S.store_ = nullptr; //RefCount supports nullptr, and S is about to be destructed
+ S.off_ = S.len_ = 0;
}
-#endif
/** Constructor: import c-style string
*
* Current SBuf will share backing store with the assigned one.
*/
SBuf& operator =(const SBuf & S) {return assign(S);}
-#if __cplusplus >= 201103L
SBuf& operator =(SBuf &&S) {
++stats.moves;
if (this != &S) {
}
return *this;
}
-#endif
/** Import a c-string into a SBuf, copying the data.
*
/** print SBuf contents and debug information about the SBuf to an ostream
*
- * Debug function, dumps to a stream informations on the current SBuf,
+ * Debug function, dumps to a stream information on the current SBuf,
* including low-level details and statistics.
*/
std::ostream& dump(std::ostream &os) const;
/** random-access read to any char within the SBuf.
*
- * \throw OutOfBoundsException when access is out of bounds
+ * \throw std::exception when access is out of bounds
* \note bounds is 0 <= pos < length(); caller must pay attention to signedness
*/
char at(size_type pos) const {checkAccessBounds(pos); return operator[](pos);}
*
* \param pos the position to be overwritten
* \param toset the value to be written
- * \throw OutOfBoundsException when pos is of bounds
+ * \throw std::exception when pos is of bounds
* \note bounds is 0 <= pos < length(); caller must pay attention to signedness
* \note performs a copy-on-write if needed.
*/
*/
SBuf consume(size_type n = npos);
- /// gets global statistic informations
+ /// gets global statistic information
static const SBufStats& GetStats();
/** Copy SBuf contents into user-supplied C buffer.
*/
const char* rawContent() const;
- /** Exports a writable pointer to the SBuf internal storage.
- * \warning Use with EXTREME caution, this is a dangerous operation.
- *
- * Returns a pointer to the first unused byte in the SBuf's storage,
- * which can be be used for appending. At least minSize bytes will
- * be available for writing.
- * The returned pointer must not be stored by the caller, as it will
- * be invalidated by the first call to a non-const method call
- * on the SBuf.
- * This call guarantees to never return NULL.
- * \see reserveSpace
- * \note Unlike reserveSpace(), this method does not guarantee exclusive
- * buffer ownership. It is instead optimized for a one writer
- * (appender), many readers scenario by avoiding unnecessary
- * copying and allocations.
- * \throw SBufTooBigException if the user tries to allocate too big a SBuf
- */
- char *rawSpace(size_type minSize);
+ /// \returns a buffer suitable for appending at most `anticipatedSize` bytes
+ /// The buffer must be used "immediately" because it is invalidated by most
+ /// non-constant SBuf method calls, including such calls against other SBuf
+ /// objects that just happen to share the same underlying MemBlob storage!
+ char *rawAppendStart(size_type anticipatedSize);
+
+ /// Updates SBuf metadata to reflect appending `actualSize` bytes to the
+ /// buffer returned by the corresponding rawAppendStart() call. Throws if
+ /// rawAppendStart(actualSize) would have returned a different value now.
+ /// \param start raw buffer previously returned by rawAppendStart()
+ /// \param actualSize the number of appended bytes
+ void rawAppendFinish(const char *start, size_type actualSize);
/** Obtain how much free space is available in the backing store.
*
*/
size_type spaceSize() const { return store_->spaceSize(); }
- /** Force a SBuf's size
- * \warning use with EXTREME caution, this is a dangerous operation
- *
- * Adapt the SBuf internal state after external interference
- * such as writing into it via rawSpace.
- * \throw TextException if SBuf doesn't have exclusive ownership of store
- * \throw SBufTooBigException if new size is bigger than available store space
- */
- void forceSize(size_type newSize);
-
/** exports a null-terminated reference to the SBuf internal storage.
* \warning ACCESSING RAW STORAGE IS DANGEROUS! DO NOT EVER USE
* THE RETURNED POINTER FOR WRITING
/** Get the length of the SBuf, as a signed integer
*
* Compatibility function for printf(3) which requires a signed int
- * \throw SBufTooBigException if the SBuf is too big for a signed integer
+ * \throw std::exception if buffer length does not fit a signed integer
*/
int plength() const {
- if (length()>INT_MAX)
- throw SBufTooBigException(__FILE__, __LINE__);
+ Must(length() <= INT_MAX);
return static_cast<int>(length());
}
* After the reserveSpace request, the SBuf is guaranteed to have at
* least minSpace bytes of unused backing store following the currently
* used portion and single ownership of the backing store.
- * \throw SBufTooBigException if the user tries to allocate too big a SBuf
+ * \throw std::exception if the user tries to allocate a too big SBuf
*/
void reserveSpace(size_type minSpace) {
Must(minSpace <= maxSize);
* minCapacity bytes of total buffer size, including the currently-used
* portion; it is also guaranteed that after this call this SBuf
* has unique ownership of the underlying memory store.
- * \throw SBufTooBigException if the user tries to allocate too big a SBuf
+ * \throw std::exception if the user tries to allocate a too big SBuf
*/
void reserveCapacity(size_type minCapacity);
+ /** Accommodate caller's requirements regarding SBuf's storage if possible.
+ *
+ * \return spaceSize(), which may be zero
+ */
+ size_type reserve(const SBufReservationRequirements &requirements);
+
/** slicing method
*
* Removes SBuf prefix and suffix, leaving a sequence of 'n'
*/
size_type findLastNotOf(const CharacterSet &set, size_type endPos = npos) const;
- /** sscanf-alike
- *
- * sscanf re-implementation. Non-const, and not \0-clean.
- * \return same as sscanf
- * \see man sscanf(3)
- */
- int scanf(const char *format, ...);
-
/// converts all characters to lower case; \see man tolower(3)
void toLower();
// TODO: possibly implement erase() similar to std::string's erase
// TODO: possibly implement a replace() call
+
+ /// SBuf object identifier meant for test cases and debugging.
+ /// Does not change when object does, including during assignment.
+ const InstanceId<SBuf> id;
+
private:
/**
friend class Locker;
MemBlob::Pointer store_; ///< memory block, possibly shared with other SBufs
- size_type off_; ///< our content start offset from the beginning of shared store_
- size_type len_; ///< number of our content bytes in shared store_
+ size_type off_ = 0; ///< our content start offset from the beginning of shared store_
+ size_type len_ = 0; ///< number of our content bytes in shared store_
static SBufStats stats; ///< class-wide statistics
- /// SBuf object identifier; does not change when contents do,
- /// including during assignment
- const InstanceId<SBuf> id;
-
/** obtain prototype store
*
* Just-created SBufs all share to the same MemBlob.
/**
* Try to guesstimate how big a MemBlob to allocate.
- * The result is guarranteed to be to be at least the desired size.
+ * The result is guaranteed to be to be at least the desired size.
*/
size_type estimateCapacity(size_type desired) const {return (2*desired);}
void cow(size_type minsize = npos);
- void checkAccessBounds(size_type pos) const;
+ void checkAccessBounds(const size_type pos) const { Must(pos < length()); }
+
+ /** Exports a writable pointer to the SBuf internal storage.
+ * \warning Use with EXTREME caution, this is a dangerous operation.
+ *
+ * Returns a pointer to the first unused byte in the SBuf's storage,
+ * which can be be used for appending. At least minSize bytes will
+ * be available for writing.
+ * The returned pointer must not be stored by the caller, as it will
+ * be invalidated by the first call to a non-const method call
+ * on the SBuf.
+ * This call guarantees to never return nullptr.
+ * \see reserveSpace
+ * \note Unlike reserveSpace(), this method does not guarantee exclusive
+ * buffer ownership. It is instead optimized for a one writer
+ * (appender), many readers scenario by avoiding unnecessary
+ * copying and allocations.
+ * \throw std::exception if the user tries to allocate a too big SBuf
+ */
+ char *rawSpace(size_type minSize);
/** Low-level append operation
*
SBuf& lowAppend(const char * memArea, size_type areaSize);
};
+/// Named SBuf::reserve() parameters. Defaults ask for and restrict nothing.
+class SBufReservationRequirements
+{
+public:
+ typedef SBuf::size_type size_type;
+
+ /*
+ * Parameters are listed in the reverse order of importance: Satisfaction of
+ * the lower-listed requirements may violate the higher-listed requirements.
+ * For example, idealSpace has no effect unless it exceeds minSpace.
+ */
+ size_type idealSpace = 0; ///< if allocating anyway, provide this much space
+ size_type minSpace = 0; ///< allocate [at least this much] if spaceSize() is smaller
+ size_type maxCapacity = SBuf::maxSize; ///< do not allocate more than this
+ bool allowShared = true; ///< whether sharing our storage with others is OK
+};
+
/// ostream output operator
inline std::ostream &
operator <<(std::ostream& os, const SBuf& S)