xstring API reference in PM123 Plugins

xstring

typedef struct
{ const char* cstr; /* pointer to C style null terminated string */
} xstring;

The xstring structure is binary compatible to a C style pointer to a constant string. The structure is only used to provide type safety.
You may read the cstr member safely as long as the xstring instance does not change asynchronously, but you must not assign it. Neither the cstr member nor the entire structure.

xstring_init

There is no such function for performance reasons. Simply initialize all xstrings with the constant xstring_NULL or use memset(..., 0, ...). But don't forget to do so and do not assign xstring_NULL to used xstrings.

xstring_create

xstring DLLENTRY xstring_create( const char* cstr );

Initialize a new xstring from a C style string. The return value can be directly assigned to a new xstring and might be used for constant xstrings. You must not use this function to assign existing, used xstrings. Use xstring_assign instead.

xstring_free

void DLLENTRY xstring_free( volatile xstring* dst );

Set the xstring to NULL and release the storage where dst points to if it is not used by another xstring instance. If *dst is NULL this is a no-op.

Calling xstring_free twice for the same object will not be an error and it is allowed to use the xstring instance afterwards normally. In fact xstring_free is equivalent to call xstring_assign with NULL.

xstring_length

unsigned DLLENTRY xstring_length( const xstring* src );
Note that this not equivalent to strlen(src->cstr). xstrings have an intrinsic length and they may contain \0 bytes. xstring_length is O(1) (unlike strlen).

xstring_equal

char DLLENTRY xstring_equal( const xstring* src1, const xstring* src2 );

Compares two instances of xstring binary. NULL strings are only equal to them self. Both strings must not change asynchronously.

Note that the result may be not the same than comparing the two strings with strcmp since xstrings may contain null bytes and differ afterwards.

The comparison only takes O(n) if both strings have the same length and do not share the same storage as copies made with xstring_copy do.

xstring_compare

int DLLENTRY xstring_compare( const xstring* src1, const xstring* src2 );

Compares two instances of xstring binary. NULL strings are less than anything else including "". Both strings must not change asynchronously.

Note that the result may be not the same than comparing the two strings with strcmp since xstrings may contain null bytes and differ afterwards.

xstring_copy

void DLLENTRY xstring_copy( volatile xstring* dst, const xstring* src );

Release the old value of *dst and place a new reference to *src into *dst. The change to *dst is atomic.

Note that xstring_copy will never copy the content of *src. It will only increment the reference count.

xstring_copy_safe

void DLLENTRY xstring_copy_safe( volatile xstring* dst, volatile const xstring* src );

xstring_copy_safe is strongly thread-safe version of xstring_copy. Fetching the value of *src and placing a strong reference to it in *dst is atomic.

Note that xstring_copy_safe will never copy the content of *src. It will only increment the reference count.

xstring_assign

void DLLENTRY xstring_assign( volatile xstring* dst, const char* cstr );

Release the old value of *dst, allocate a new xstring, initialize it with the content of cstr and assign it to *dst. If cstr is NULL *dst is cleared. The change to *dst is atomic.

xstring_cmpassign

char DLLENTRY xstring_cmpassign( xstring* dst, const char* cstr );

Copies the value of cstr into *dst if and only if the strings are different. This is useful to keep track of changes. Furthermore if the storage of *dst is shared with other xstring instances, an assignment of an identical string will not destroy the storage sharing.

xstring_append

void DLLENTRY xstring_append( xstring* dst, const char* cstr );

Appends the string *src to *dst. Both must not be NULL. The operation is not atomic.

You should avoid repeated calls to xstring_append to concatenate multiple strings for performance reasons. This will in total perform O(n2). It is better to allocate the required storage at once with xstring_allocate and fill the content afterwards.

xstring_allocate

char* DLLENTRY xstring_allocate( xstring* dst, unsigned int len );

Allocate a new xstring with uninitialized storage of len characters and assign it to *dst. The old value of *dst is freed. The returned value is always the same as the new value of dst->cstr except for constness.

You may then write up to len characters to the memory where the return value points to. It is allowed to write one additional \0 byte behind the len characters, but no other value must be placed there. The null byte is initialized by xstring_alloc anyway.

You may modify the returned memory until the next xstring API function call for *dst.

xstring_sprintf, xstring_vsprintf

void DLLENTRY xstring_sprintf( volatile xstring* dst, const char* fmt, ... );
void DLLENTRY xstring_vsprintf( volatile xstring* dst, const char* fmt, va_list va );

Release the old value of *dst and place a formatted output into *dst. The behavior of this functions is similar to sprintf/vsprintf but unlike the C library functions these functions are safe with respect to the length of the returned string. They will always allocate enough memory automatically.

xstring_deduplicate

void DLLENTRY xstring_deduplicate( volatile xstring* dst );

The string is put into an internal repository of PM123 and if a match is found the instance is replaced by the instance in the repository and the current instance is discarded. The operation is atomic.

Deduplication means that value equality is turned into reference equality. Since the referenced content of xstrings is immutable this is always safe. This could dramatically reduce the memory footprint of PM123 if many identical strings are held at different places.

However deduplication also takes additional resources. Approximately 6 bytes for the repository entry and CPU for the dictionary lookup. The repository has to be locked forthe deduplication . So be careful where you use it. Also note the the meta data of songs returned by decoder plugins is automatically deduplicated. In general you should only care about string that are local to your plugin.