Alien-libpanda
view release on metacpan or search on metacpan
src/panda/basic_string.h view on Meta::CPAN
#pragma once
#include "hash.h"
#include "from_chars.h"
#include "string_view.h"
#include <string>
#include <limits>
#include <memory>
#include <iosfwd>
#include <utility> // swap
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <iterator>
#include <stdexcept>
#include <initializer_list>
namespace panda {
/*
* panda::string is an std::string drop-in replacement which has the same API but is much more flexible and allows for behaviors that in other case
* would lead to a lot of unnecessary allocations/copying.
*
* Most important features are:
*
* - Copy-On-Write support (COW).
* Not only when assigning the whole string but also when any form of substr() is applied.
* If any of the COW copies is trying to change, it detaches from the original string, copying the content it needs.
* - External static string support.
* Can be created from external static(immortal) data without allocating memory and copying it.
* String will be allocated and copied when you first try to change it.
* For example if a function accepts string, you may pass it just a string literal "hello" and nothing is allocated or copied and even the length
* is counted in compile time.
* - External dynamic string support.
* Can be created from external dynamic(mortal) data without allocating memory and copying it.
* External data will be deallocated via custom destructor when the last string that references to the external data is lost.
* As for any other subtype of panda::string copying/substr/etc of such string does not copy anything
* - SSO support (small string optimization). Up to 23 bytes for 64bit / 11 bytes for 32bit.
* It does not mean that all strings <= MAX_SSO_CHARS are in SSO mode. SSO mode is used only when otherwise panda::string would have to allocate
* and copy something. For example if you call "otherstr = mystr.substr(offset, len)", then otherstr will not use SSO even if len <= MAX_SSO_CHARS,
* because it prefers to do nothing (COW-mode) instead of copying content to SSO location.
* - Support for getting r/w internal data buffer to manually fill it.
* The content of other strings which shares the data with current string will not be affected.
* - Reallocate instead of deallocate/allocate when possible, which in many cases is much faster
* - Supports auto convertations between basic_strings with different Allocator template parameter without copying and allocating anything.
* For example any basic_string<...> can be assigned to/from string as if they were of the same class.
*
* All these features covers almost all generic use cases, including creating zero-copy cascade parsers which in other case would lead to a lot of
* pain.
*
* c_str() is not supported, because strings are not null-terminated
*/
namespace string_detail {
template <typename S>
struct mutable_charref {
using value_type = typename S::value_type;
using size_type = typename S::size_type;
mutable_charref (S& string, size_type pos): _string(string), _pos(pos) {}
template <typename Arg, typename = std::enable_if_t<std::is_convertible<Arg, value_type>::value>>
mutable_charref& operator= (Arg&& value) {
_string._detach();
_string._str[_pos] = std::forward<Arg>(value);
return *this;
}
operator value_type() const { return _string._str[_pos]; }
private:
S& _string;
size_type _pos;
};
enum class State : uint8_t {
INTERNAL, // has InternalBuffer, may have _storage.dtor in case of basic_string<A,B,X> <-> basic_string<A,B,Y> convertations
EXTERNAL, // has ExternalShared, shares external data, _storage.dtor present, _storage.external->dtor present
LITERAL, // shares external data, no Buffer, no _storage.dtor (literal data is immortal)
SSO // owns small string, no Buffer, no _storage.dtor
};
template <class CharT>
struct Buffer {
size_t capacity;
uint32_t refcnt;
CharT start[(sizeof(void*)-4)/sizeof(CharT)]; // align to word size
};
template <class CharT>
struct ExternalShared : Buffer<CharT> {
using dtor_fn = void (*)(CharT*, size_t);
dtor_fn dtor; // deallocator for ExternalShared, may differ from Alloc::deallocate !
CharT* ptr; // pointer to external data originally passed to string's constructor
};
}
template <class T>
struct DefaultStaticAllocator {
typedef T value_type;
static T* allocate (size_t n) {
void* mem = malloc(n * sizeof(T));
if (!mem) throw std::bad_alloc();
return (T*)mem;
}
static void deallocate (T* mem, size_t) {
( run in 0.593 second using v1.01-cache-2.11-cpan-119454b85a5 )