ralloc.h revision af69d88d
1af69d88dSmrg/* 2af69d88dSmrg * Copyright © 2010 Intel Corporation 3af69d88dSmrg * 4af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 6af69d88dSmrg * to deal in the Software without restriction, including without limitation 7af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 10af69d88dSmrg * 11af69d88dSmrg * The above copyright notice and this permission notice (including the next 12af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the 13af69d88dSmrg * Software. 14af69d88dSmrg * 15af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20af69d88dSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21af69d88dSmrg * DEALINGS IN THE SOFTWARE. 22af69d88dSmrg */ 23af69d88dSmrg 24af69d88dSmrg/** 25af69d88dSmrg * \file ralloc.h 26af69d88dSmrg * 27af69d88dSmrg * ralloc: a recursive memory allocator 28af69d88dSmrg * 29af69d88dSmrg * The ralloc memory allocator creates a hierarchy of allocated 30af69d88dSmrg * objects. Every allocation is in reference to some parent, and 31af69d88dSmrg * every allocated object can in turn be used as the parent of a 32af69d88dSmrg * subsequent allocation. This allows for extremely convenient 33af69d88dSmrg * discarding of an entire tree/sub-tree of allocations by calling 34af69d88dSmrg * ralloc_free on any particular object to free it and all of its 35af69d88dSmrg * children. 36af69d88dSmrg * 37af69d88dSmrg * The conceptual working of ralloc was directly inspired by Andrew 38af69d88dSmrg * Tridgell's talloc, but ralloc is an independent implementation 39af69d88dSmrg * released under the MIT license and tuned for Mesa. 40af69d88dSmrg * 41af69d88dSmrg * talloc is more sophisticated than ralloc in that it includes reference 42af69d88dSmrg * counting and useful debugging features. However, it is released under 43af69d88dSmrg * a non-permissive open source license. 44af69d88dSmrg */ 45af69d88dSmrg 46af69d88dSmrg#ifndef RALLOC_H 47af69d88dSmrg#define RALLOC_H 48af69d88dSmrg 49af69d88dSmrg#ifdef __cplusplus 50af69d88dSmrgextern "C" { 51af69d88dSmrg#endif 52af69d88dSmrg 53af69d88dSmrg#include <stddef.h> 54af69d88dSmrg#include <stdarg.h> 55af69d88dSmrg#include <stdbool.h> 56af69d88dSmrg 57af69d88dSmrg#include "macros.h" 58af69d88dSmrg 59af69d88dSmrg/** 60af69d88dSmrg * \def ralloc(ctx, type) 61af69d88dSmrg * Allocate a new object chained off of the given context. 62af69d88dSmrg * 63af69d88dSmrg * This is equivalent to: 64af69d88dSmrg * \code 65af69d88dSmrg * ((type *) ralloc_size(ctx, sizeof(type)) 66af69d88dSmrg * \endcode 67af69d88dSmrg */ 68af69d88dSmrg#define ralloc(ctx, type) ((type *) ralloc_size(ctx, sizeof(type))) 69af69d88dSmrg 70af69d88dSmrg/** 71af69d88dSmrg * \def rzalloc(ctx, type) 72af69d88dSmrg * Allocate a new object out of the given context and initialize it to zero. 73af69d88dSmrg * 74af69d88dSmrg * This is equivalent to: 75af69d88dSmrg * \code 76af69d88dSmrg * ((type *) rzalloc_size(ctx, sizeof(type)) 77af69d88dSmrg * \endcode 78af69d88dSmrg */ 79af69d88dSmrg#define rzalloc(ctx, type) ((type *) rzalloc_size(ctx, sizeof(type))) 80af69d88dSmrg 81af69d88dSmrg/** 82af69d88dSmrg * Allocate a new ralloc context. 83af69d88dSmrg * 84af69d88dSmrg * While any ralloc'd pointer can be used as a context, sometimes it is useful 85af69d88dSmrg * to simply allocate a context with no associated memory. 86af69d88dSmrg * 87af69d88dSmrg * It is equivalent to: 88af69d88dSmrg * \code 89af69d88dSmrg * ((type *) ralloc_size(ctx, 0) 90af69d88dSmrg * \endcode 91af69d88dSmrg */ 92af69d88dSmrgvoid *ralloc_context(const void *ctx); 93af69d88dSmrg 94af69d88dSmrg/** 95af69d88dSmrg * Allocate memory chained off of the given context. 96af69d88dSmrg * 97af69d88dSmrg * This is the core allocation routine which is used by all others. It 98af69d88dSmrg * simply allocates storage for \p size bytes and returns the pointer, 99af69d88dSmrg * similar to \c malloc. 100af69d88dSmrg */ 101af69d88dSmrgvoid *ralloc_size(const void *ctx, size_t size); 102af69d88dSmrg 103af69d88dSmrg/** 104af69d88dSmrg * Allocate zero-initialized memory chained off of the given context. 105af69d88dSmrg * 106af69d88dSmrg * This is similar to \c calloc with a size of 1. 107af69d88dSmrg */ 108af69d88dSmrgvoid *rzalloc_size(const void *ctx, size_t size); 109af69d88dSmrg 110af69d88dSmrg/** 111af69d88dSmrg * Resize a piece of ralloc-managed memory, preserving data. 112af69d88dSmrg * 113af69d88dSmrg * Similar to \c realloc. Unlike C89, passing 0 for \p size does not free the 114af69d88dSmrg * memory. Instead, it resizes it to a 0-byte ralloc context, just like 115af69d88dSmrg * calling ralloc_size(ctx, 0). This is different from talloc. 116af69d88dSmrg * 117af69d88dSmrg * \param ctx The context to use for new allocation. If \p ptr != NULL, 118af69d88dSmrg * it must be the same as ralloc_parent(\p ptr). 119af69d88dSmrg * \param ptr Pointer to the memory to be resized. May be NULL. 120af69d88dSmrg * \param size The amount of memory to allocate, in bytes. 121af69d88dSmrg */ 122af69d88dSmrgvoid *reralloc_size(const void *ctx, void *ptr, size_t size); 123af69d88dSmrg 124af69d88dSmrg/// \defgroup array Array Allocators @{ 125af69d88dSmrg 126af69d88dSmrg/** 127af69d88dSmrg * \def ralloc_array(ctx, type, count) 128af69d88dSmrg * Allocate an array of objects chained off the given context. 129af69d88dSmrg * 130af69d88dSmrg * Similar to \c calloc, but does not initialize the memory to zero. 131af69d88dSmrg * 132af69d88dSmrg * More than a convenience function, this also checks for integer overflow when 133af69d88dSmrg * multiplying \c sizeof(type) and \p count. This is necessary for security. 134af69d88dSmrg * 135af69d88dSmrg * This is equivalent to: 136af69d88dSmrg * \code 137af69d88dSmrg * ((type *) ralloc_array_size(ctx, sizeof(type), count) 138af69d88dSmrg * \endcode 139af69d88dSmrg */ 140af69d88dSmrg#define ralloc_array(ctx, type, count) \ 141af69d88dSmrg ((type *) ralloc_array_size(ctx, sizeof(type), count)) 142af69d88dSmrg 143af69d88dSmrg/** 144af69d88dSmrg * \def rzalloc_array(ctx, type, count) 145af69d88dSmrg * Allocate a zero-initialized array chained off the given context. 146af69d88dSmrg * 147af69d88dSmrg * Similar to \c calloc. 148af69d88dSmrg * 149af69d88dSmrg * More than a convenience function, this also checks for integer overflow when 150af69d88dSmrg * multiplying \c sizeof(type) and \p count. This is necessary for security. 151af69d88dSmrg * 152af69d88dSmrg * This is equivalent to: 153af69d88dSmrg * \code 154af69d88dSmrg * ((type *) rzalloc_array_size(ctx, sizeof(type), count) 155af69d88dSmrg * \endcode 156af69d88dSmrg */ 157af69d88dSmrg#define rzalloc_array(ctx, type, count) \ 158af69d88dSmrg ((type *) rzalloc_array_size(ctx, sizeof(type), count)) 159af69d88dSmrg 160af69d88dSmrg/** 161af69d88dSmrg * \def reralloc(ctx, ptr, type, count) 162af69d88dSmrg * Resize a ralloc-managed array, preserving data. 163af69d88dSmrg * 164af69d88dSmrg * Similar to \c realloc. Unlike C89, passing 0 for \p size does not free the 165af69d88dSmrg * memory. Instead, it resizes it to a 0-byte ralloc context, just like 166af69d88dSmrg * calling ralloc_size(ctx, 0). This is different from talloc. 167af69d88dSmrg * 168af69d88dSmrg * More than a convenience function, this also checks for integer overflow when 169af69d88dSmrg * multiplying \c sizeof(type) and \p count. This is necessary for security. 170af69d88dSmrg * 171af69d88dSmrg * \param ctx The context to use for new allocation. If \p ptr != NULL, 172af69d88dSmrg * it must be the same as ralloc_parent(\p ptr). 173af69d88dSmrg * \param ptr Pointer to the array to be resized. May be NULL. 174af69d88dSmrg * \param type The element type. 175af69d88dSmrg * \param count The number of elements to allocate. 176af69d88dSmrg */ 177af69d88dSmrg#define reralloc(ctx, ptr, type, count) \ 178af69d88dSmrg ((type *) reralloc_array_size(ctx, ptr, sizeof(type), count)) 179af69d88dSmrg 180af69d88dSmrg/** 181af69d88dSmrg * Allocate memory for an array chained off the given context. 182af69d88dSmrg * 183af69d88dSmrg * Similar to \c calloc, but does not initialize the memory to zero. 184af69d88dSmrg * 185af69d88dSmrg * More than a convenience function, this also checks for integer overflow when 186af69d88dSmrg * multiplying \p size and \p count. This is necessary for security. 187af69d88dSmrg */ 188af69d88dSmrgvoid *ralloc_array_size(const void *ctx, size_t size, unsigned count); 189af69d88dSmrg 190af69d88dSmrg/** 191af69d88dSmrg * Allocate a zero-initialized array chained off the given context. 192af69d88dSmrg * 193af69d88dSmrg * Similar to \c calloc. 194af69d88dSmrg * 195af69d88dSmrg * More than a convenience function, this also checks for integer overflow when 196af69d88dSmrg * multiplying \p size and \p count. This is necessary for security. 197af69d88dSmrg */ 198af69d88dSmrgvoid *rzalloc_array_size(const void *ctx, size_t size, unsigned count); 199af69d88dSmrg 200af69d88dSmrg/** 201af69d88dSmrg * Resize a ralloc-managed array, preserving data. 202af69d88dSmrg * 203af69d88dSmrg * Similar to \c realloc. Unlike C89, passing 0 for \p size does not free the 204af69d88dSmrg * memory. Instead, it resizes it to a 0-byte ralloc context, just like 205af69d88dSmrg * calling ralloc_size(ctx, 0). This is different from talloc. 206af69d88dSmrg * 207af69d88dSmrg * More than a convenience function, this also checks for integer overflow when 208af69d88dSmrg * multiplying \c sizeof(type) and \p count. This is necessary for security. 209af69d88dSmrg * 210af69d88dSmrg * \param ctx The context to use for new allocation. If \p ptr != NULL, 211af69d88dSmrg * it must be the same as ralloc_parent(\p ptr). 212af69d88dSmrg * \param ptr Pointer to the array to be resized. May be NULL. 213af69d88dSmrg * \param size The size of an individual element. 214af69d88dSmrg * \param count The number of elements to allocate. 215af69d88dSmrg * 216af69d88dSmrg * \return True unless allocation failed. 217af69d88dSmrg */ 218af69d88dSmrgvoid *reralloc_array_size(const void *ctx, void *ptr, size_t size, 219af69d88dSmrg unsigned count); 220af69d88dSmrg/// @} 221af69d88dSmrg 222af69d88dSmrg/** 223af69d88dSmrg * Free a piece of ralloc-managed memory. 224af69d88dSmrg * 225af69d88dSmrg * This will also free the memory of any children allocated this context. 226af69d88dSmrg */ 227af69d88dSmrgvoid ralloc_free(void *ptr); 228af69d88dSmrg 229af69d88dSmrg/** 230af69d88dSmrg * "Steal" memory from one context, changing it to another. 231af69d88dSmrg * 232af69d88dSmrg * This changes \p ptr's context to \p new_ctx. This is quite useful if 233af69d88dSmrg * memory is allocated out of a temporary context. 234af69d88dSmrg */ 235af69d88dSmrgvoid ralloc_steal(const void *new_ctx, void *ptr); 236af69d88dSmrg 237af69d88dSmrg/** 238af69d88dSmrg * Return the given pointer's ralloc context. 239af69d88dSmrg */ 240af69d88dSmrgvoid *ralloc_parent(const void *ptr); 241af69d88dSmrg 242af69d88dSmrg/** 243af69d88dSmrg * Return a context whose memory will be automatically freed at program exit. 244af69d88dSmrg * 245af69d88dSmrg * The first call to this function creates a context and registers a handler 246af69d88dSmrg * to free it using \c atexit. This may cause trouble if used in a library 247af69d88dSmrg * loaded with \c dlopen. 248af69d88dSmrg */ 249af69d88dSmrgvoid *ralloc_autofree_context(void); 250af69d88dSmrg 251af69d88dSmrg/** 252af69d88dSmrg * Set a callback to occur just before an object is freed. 253af69d88dSmrg */ 254af69d88dSmrgvoid ralloc_set_destructor(const void *ptr, void(*destructor)(void *)); 255af69d88dSmrg 256af69d88dSmrg/// \defgroup array String Functions @{ 257af69d88dSmrg/** 258af69d88dSmrg * Duplicate a string, allocating the memory from the given context. 259af69d88dSmrg */ 260af69d88dSmrgchar *ralloc_strdup(const void *ctx, const char *str); 261af69d88dSmrg 262af69d88dSmrg/** 263af69d88dSmrg * Duplicate a string, allocating the memory from the given context. 264af69d88dSmrg * 265af69d88dSmrg * Like \c strndup, at most \p n characters are copied. If \p str is longer 266af69d88dSmrg * than \p n characters, \p n are copied, and a termining \c '\0' byte is added. 267af69d88dSmrg */ 268af69d88dSmrgchar *ralloc_strndup(const void *ctx, const char *str, size_t n); 269af69d88dSmrg 270af69d88dSmrg/** 271af69d88dSmrg * Concatenate two strings, allocating the necessary space. 272af69d88dSmrg * 273af69d88dSmrg * This appends \p str to \p *dest, similar to \c strcat, using ralloc_resize 274af69d88dSmrg * to expand \p *dest to the appropriate size. \p dest will be updated to the 275af69d88dSmrg * new pointer unless allocation fails. 276af69d88dSmrg * 277af69d88dSmrg * The result will always be null-terminated. 278af69d88dSmrg * 279af69d88dSmrg * \return True unless allocation failed. 280af69d88dSmrg */ 281af69d88dSmrgbool ralloc_strcat(char **dest, const char *str); 282af69d88dSmrg 283af69d88dSmrg/** 284af69d88dSmrg * Concatenate two strings, allocating the necessary space. 285af69d88dSmrg * 286af69d88dSmrg * This appends at most \p n bytes of \p str to \p *dest, using ralloc_resize 287af69d88dSmrg * to expand \p *dest to the appropriate size. \p dest will be updated to the 288af69d88dSmrg * new pointer unless allocation fails. 289af69d88dSmrg * 290af69d88dSmrg * The result will always be null-terminated; \p str does not need to be null 291af69d88dSmrg * terminated if it is longer than \p n. 292af69d88dSmrg * 293af69d88dSmrg * \return True unless allocation failed. 294af69d88dSmrg */ 295af69d88dSmrgbool ralloc_strncat(char **dest, const char *str, size_t n); 296af69d88dSmrg 297af69d88dSmrg/** 298af69d88dSmrg * Print to a string. 299af69d88dSmrg * 300af69d88dSmrg * This is analogous to \c sprintf, but allocates enough space (using \p ctx 301af69d88dSmrg * as the context) for the resulting string. 302af69d88dSmrg * 303af69d88dSmrg * \return The newly allocated string. 304af69d88dSmrg */ 305af69d88dSmrgchar *ralloc_asprintf (const void *ctx, const char *fmt, ...) PRINTFLIKE(2, 3); 306af69d88dSmrg 307af69d88dSmrg/** 308af69d88dSmrg * Print to a string, given a va_list. 309af69d88dSmrg * 310af69d88dSmrg * This is analogous to \c vsprintf, but allocates enough space (using \p ctx 311af69d88dSmrg * as the context) for the resulting string. 312af69d88dSmrg * 313af69d88dSmrg * \return The newly allocated string. 314af69d88dSmrg */ 315af69d88dSmrgchar *ralloc_vasprintf(const void *ctx, const char *fmt, va_list args); 316af69d88dSmrg 317af69d88dSmrg/** 318af69d88dSmrg * Rewrite the tail of an existing string, starting at a given index. 319af69d88dSmrg * 320af69d88dSmrg * Overwrites the contents of *str starting at \p start with newly formatted 321af69d88dSmrg * text, including a new null-terminator. Allocates more memory as necessary. 322af69d88dSmrg * 323af69d88dSmrg * This can be used to append formatted text when the length of the existing 324af69d88dSmrg * string is already known, saving a strlen() call. 325af69d88dSmrg * 326af69d88dSmrg * \sa ralloc_asprintf_append 327af69d88dSmrg * 328af69d88dSmrg * \param str The string to be updated. 329af69d88dSmrg * \param start The index to start appending new data at. 330af69d88dSmrg * \param fmt A printf-style formatting string 331af69d88dSmrg * 332af69d88dSmrg * \p str will be updated to the new pointer unless allocation fails. 333af69d88dSmrg * \p start will be increased by the length of the newly formatted text. 334af69d88dSmrg * 335af69d88dSmrg * \return True unless allocation failed. 336af69d88dSmrg */ 337af69d88dSmrgbool ralloc_asprintf_rewrite_tail(char **str, size_t *start, 338af69d88dSmrg const char *fmt, ...) 339af69d88dSmrg PRINTFLIKE(3, 4); 340af69d88dSmrg 341af69d88dSmrg/** 342af69d88dSmrg * Rewrite the tail of an existing string, starting at a given index. 343af69d88dSmrg * 344af69d88dSmrg * Overwrites the contents of *str starting at \p start with newly formatted 345af69d88dSmrg * text, including a new null-terminator. Allocates more memory as necessary. 346af69d88dSmrg * 347af69d88dSmrg * This can be used to append formatted text when the length of the existing 348af69d88dSmrg * string is already known, saving a strlen() call. 349af69d88dSmrg * 350af69d88dSmrg * \sa ralloc_vasprintf_append 351af69d88dSmrg * 352af69d88dSmrg * \param str The string to be updated. 353af69d88dSmrg * \param start The index to start appending new data at. 354af69d88dSmrg * \param fmt A printf-style formatting string 355af69d88dSmrg * \param args A va_list containing the data to be formatted 356af69d88dSmrg * 357af69d88dSmrg * \p str will be updated to the new pointer unless allocation fails. 358af69d88dSmrg * \p start will be increased by the length of the newly formatted text. 359af69d88dSmrg * 360af69d88dSmrg * \return True unless allocation failed. 361af69d88dSmrg */ 362af69d88dSmrgbool ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt, 363af69d88dSmrg va_list args); 364af69d88dSmrg 365af69d88dSmrg/** 366af69d88dSmrg * Append formatted text to the supplied string. 367af69d88dSmrg * 368af69d88dSmrg * This is equivalent to 369af69d88dSmrg * \code 370af69d88dSmrg * ralloc_asprintf_rewrite_tail(str, strlen(*str), fmt, ...) 371af69d88dSmrg * \endcode 372af69d88dSmrg * 373af69d88dSmrg * \sa ralloc_asprintf 374af69d88dSmrg * \sa ralloc_asprintf_rewrite_tail 375af69d88dSmrg * \sa ralloc_strcat 376af69d88dSmrg * 377af69d88dSmrg * \p str will be updated to the new pointer unless allocation fails. 378af69d88dSmrg * 379af69d88dSmrg * \return True unless allocation failed. 380af69d88dSmrg */ 381af69d88dSmrgbool ralloc_asprintf_append (char **str, const char *fmt, ...) 382af69d88dSmrg PRINTFLIKE(2, 3); 383af69d88dSmrg 384af69d88dSmrg/** 385af69d88dSmrg * Append formatted text to the supplied string, given a va_list. 386af69d88dSmrg * 387af69d88dSmrg * This is equivalent to 388af69d88dSmrg * \code 389af69d88dSmrg * ralloc_vasprintf_rewrite_tail(str, strlen(*str), fmt, args) 390af69d88dSmrg * \endcode 391af69d88dSmrg * 392af69d88dSmrg * \sa ralloc_vasprintf 393af69d88dSmrg * \sa ralloc_vasprintf_rewrite_tail 394af69d88dSmrg * \sa ralloc_strcat 395af69d88dSmrg * 396af69d88dSmrg * \p str will be updated to the new pointer unless allocation fails. 397af69d88dSmrg * 398af69d88dSmrg * \return True unless allocation failed. 399af69d88dSmrg */ 400af69d88dSmrgbool ralloc_vasprintf_append(char **str, const char *fmt, va_list args); 401af69d88dSmrg/// @} 402af69d88dSmrg 403af69d88dSmrg#ifdef __cplusplus 404af69d88dSmrg} /* end of extern "C" */ 405af69d88dSmrg#endif 406af69d88dSmrg 407af69d88dSmrg/** 408af69d88dSmrg * Declare C++ new and delete operators which use ralloc. 409af69d88dSmrg * 410af69d88dSmrg * Placing this macro in the body of a class makes it possible to do: 411af69d88dSmrg * 412af69d88dSmrg * TYPE *var = new(mem_ctx) TYPE(...); 413af69d88dSmrg * delete var; 414af69d88dSmrg * 415af69d88dSmrg * which is more idiomatic in C++ than calling ralloc. 416af69d88dSmrg */ 417af69d88dSmrg#define DECLARE_RALLOC_CXX_OPERATORS(TYPE) \ 418af69d88dSmrgprivate: \ 419af69d88dSmrg static void _ralloc_destructor(void *p) \ 420af69d88dSmrg { \ 421af69d88dSmrg reinterpret_cast<TYPE *>(p)->~TYPE(); \ 422af69d88dSmrg } \ 423af69d88dSmrgpublic: \ 424af69d88dSmrg static void* operator new(size_t size, void *mem_ctx) \ 425af69d88dSmrg { \ 426af69d88dSmrg void *p = ralloc_size(mem_ctx, size); \ 427af69d88dSmrg assert(p != NULL); \ 428af69d88dSmrg if (!HAS_TRIVIAL_DESTRUCTOR(TYPE)) \ 429af69d88dSmrg ralloc_set_destructor(p, _ralloc_destructor); \ 430af69d88dSmrg return p; \ 431af69d88dSmrg } \ 432af69d88dSmrg \ 433af69d88dSmrg static void operator delete(void *p) \ 434af69d88dSmrg { \ 435af69d88dSmrg /* The object's destructor is guaranteed to have already been \ 436af69d88dSmrg * called by the delete operator at this point -- Make sure it's \ 437af69d88dSmrg * not called again. \ 438af69d88dSmrg */ \ 439af69d88dSmrg if (!HAS_TRIVIAL_DESTRUCTOR(TYPE)) \ 440af69d88dSmrg ralloc_set_destructor(p, NULL); \ 441af69d88dSmrg ralloc_free(p); \ 442af69d88dSmrg } 443af69d88dSmrg 444af69d88dSmrg 445af69d88dSmrg#endif 446