新增sds.c sds.h zmalloc.c部分注释

This commit is contained in:
zhuyijun 2021-11-06 14:02:40 +08:00
parent 37273e0dd8
commit 1b901cf01a
3 changed files with 336 additions and 35 deletions

325
src/sds.c
View File

@ -63,7 +63,7 @@ static inline int sdsHdrSize(char type) {
return 0;
}
/**
* sds字符串长度获取sds类型
* sds字符串长度获取所需要的sds类型
* @param string_size
* @return
*/
@ -213,7 +213,7 @@ sds _sdsnewlen(const void *init, size_t initlen, int trymalloc) {
return s;
}
/**
* sds字符串
* sds字符串 使s_malloc_usable创建内存空间
* @param init
* @param initlen
* @return
@ -222,7 +222,7 @@ sds sdsnewlen(const void *init, size_t initlen) {
return _sdsnewlen(init, initlen, 0);
}
/**
*
* sds使s_trymalloc_usable创建内存空间
* @param init
* @param initlen
* @return
@ -230,27 +230,44 @@ sds sdsnewlen(const void *init, size_t initlen) {
sds sdstrynewlen(const void *init, size_t initlen) {
return _sdsnewlen(init, initlen, 1);
}
/**
* 0
* @return sds字符串
*/
/* Create an empty (zero length) sds string. Even in this case the string
* always has an implicit null term. */
sds sdsempty(void) {
return sdsnewlen("",0);
}
/**
* null结尾的 C字符串 sds字符串
* @param init
* @return
*/
/* Create a new sds string starting from a null terminated C string. */
sds sdsnew(const char *init) {
// 判断传入的字符串是否为NULL 如果为NULL为创建一个空的sds字符串否则创建strlen(init)长度的sds字符串
size_t initlen = (init == NULL) ? 0 : strlen(init);
return sdsnewlen(init, initlen);
}
/**
* sds
* @param s
* @return
*/
/* Duplicate an sds string. */
sds sdsdup(const sds s) {
return sdsnewlen(s, sdslen(s));
}
/**
* sds字符串
* @param s sds字符串
*/
/* Free an sds string. No operation is performed if 's' is NULL. */
void sdsfree(sds s) {
//如果sds字符串为NULL为不作操作
if (s == NULL) return;
//释放内存空间
s_free((char*)s-sdsHdrSize(s[-1]));
}
@ -268,8 +285,24 @@ void sdsfree(sds s) {
* The output will be "2", but if we comment out the call to sdsupdatelen()
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
/**
* sds的已经使用的长度修改成第一个'\0'\0
*
* sds字符串中某一个字符为'\0'
* sds字符串长度sds长度记录在sds头len中sds长度不变
*
* s = sdsnew("foobar");
* s[2] = '\0';
* dsupdatelen(s);
* rintf("%d\n", sdslen(s));
* 2
* dsupdatelen(s); sds长度还是原来的6
* @param s
*/
void sdsupdatelen(sds s) {
//获取sds长度即 到第一个'\0'的长度
size_t reallen = strlen(s);
// 给sds设置新的长度
sdssetlen(s, reallen);
}
@ -277,6 +310,11 @@ void sdsupdatelen(sds s) {
* However all the existing buffer is not discarded but set as free space
* so that next append operations will not require allocations up to the
* number of bytes previously available. */
/**
* sds的内存清零但不释放
* sds长度为0 '\0'
* @param s
*/
void sdsclear(sds s) {
sdssetlen(s, 0);
s[0] = '\0';
@ -288,53 +326,79 @@ void sdsclear(sds s) {
*
* Note: this does not change the *length* of the sds string as returned
* by sdslen(), but only the free buffer space we have. */
/**
* sds扩充空间以供以后使用
* sds字符串sds的alloc的小
* @param s sds字符串
* @param addlen
* @return sds字符串
*/
sds sdsMakeRoomFor(sds s, size_t addlen) {
void *sh, *newsh;
//获取sds当前可用空间
size_t avail = sdsavail(s);
size_t len, newlen, reqlen;
//获取sds的类型 s[-1]= flags oldtype = flags & SDS_TYPE_MASK;
char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen;
size_t usable;
//如果可用空间大于扩容大小 则无须扩容直接返回
/* Return ASAP if there is enough space left. */
if (avail >= addlen) return s;
//判断字符串长度
len = sdslen(s);
//获取sds类型结构占用的内存大小
sh = (char*)s-sdsHdrSize(oldtype);
//新的内存大小等于 sds字符串长度+新增长度
reqlen = newlen = (len+addlen);
//断言 新增后的长度要大于 sds字符串长度
assert(newlen > len); /* Catch size_t overflow */
//如果新的长度小于 1M,则扩容为其2倍
if (newlen < SDS_MAX_PREALLOC)
newlen *= 2;
//否则+1M
else
newlen += SDS_MAX_PREALLOC;
//修改要扩容sds字符串的类型
type = sdsReqType(newlen);
/* Don't use type 5: the user is appending to the string and type 5 is
* not able to remember empty space, so sdsMakeRoomFor() must be called
* at every appending operation. */
//如果类型是SDS_TYPE_5 的话将类型设置为 SDS_TYPE_8
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
//获取新的类型的结构占用的空间大小
hdrlen = sdsHdrSize(type);
//断言 新的类型结构占用的空间 + 扩容后的长度+1 要大于 扩容前sds字符串长度+addlen新增长度
assert(hdrlen + newlen + 1 > reqlen); /* Catch size_t overflow */
if (oldtype==type) {
//如果旧的类型和新的类型一致,则重新分配内存
newsh = s_realloc_usable(sh, hdrlen+newlen+1, &usable);
if (newsh == NULL) return NULL;
s = (char*)newsh+hdrlen;
} else {
/* Since the header size changes, need to move the string forward,
* and can't use realloc */
//如果新类型和旧内存不一致则重新创建一个新的内存空间
//分配内存 如果为NULL则内存分配失败 否则usable为可用内存大小
newsh = s_malloc_usable(hdrlen+newlen+1, &usable);
if (newsh == NULL) return NULL;
//复制字符串
memcpy((char*)newsh+hdrlen, s, len+1);
//释放之前的sds字符串
s_free(sh);
s = (char*)newsh+hdrlen;
//设置新标识
s[-1] = type;
//给sds设置新的长度
sdssetlen(s, len);
}
//可用内存 = 分配的可用内存-sds类型结构内存-1
usable = usable-hdrlen-1;
//如果可用内存 > 类型最大的内存则重新设置sds类型
if (usable > sdsTypeMaxSize(type))
usable = sdsTypeMaxSize(type);
//设置字符串可用内存为新分配的内存
sdssetalloc(s, usable);
return s;
}
@ -345,20 +409,32 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
*
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
/**
* 使sds的分配内存 sds可用空间为0
* sds字符串内存空间s字符串将不可以sds字符串
* @param s sds字符串
* @return
*/
sds sdsRemoveFreeSpace(sds s) {
void *sh, *newsh;
//s[-1] = flags sds类型
char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
//获取sds字符串长度
size_t len = sdslen(s);
//获取s的可用内存
size_t avail = sdsavail(s);
//sda的buf长度 = sds长度 - sds类型结构占用的内存空间大小
sh = (char*)s-oldhdrlen;
//如果可用空间已经为0那么无须调整
/* Return ASAP if there is no space left. */
if (avail == 0) return s;
/* Check what would be the minimum SDS header that is just good enough to
* fit this string. */
//获取该长度所需要的的sds类型
type = sdsReqType(len);
//获取sds类型结构占用的内存大小
hdrlen = sdsHdrSize(type);
/* If the type is the same, or at least a large enough type is still
@ -366,18 +442,29 @@ sds sdsRemoveFreeSpace(sds s) {
* only if really needed. Otherwise if the change is huge, we manually
* reallocate the string to use the different header type. */
if (oldtype==type || type > SDS_TYPE_8) {
//如果旧sds类型和 sds字符串最少需要的sds类型一致,重新分配内存并将之前sds内存释放
newsh = s_realloc(sh, oldhdrlen+len+1);
//如果分配失败则返回NULL
if (newsh == NULL) return NULL;
//c 字符串
s = (char*)newsh+oldhdrlen;
} else {
//sds字符串最少需要空间的sds类型 和 原sds类型不一致 分配内存
newsh = s_malloc(hdrlen+len+1);
//如果为NULL则分配失败
if (newsh == NULL) return NULL;
//复制
memcpy((char*)newsh+hdrlen, s, len+1);
//释放原sds串内存
s_free(sh);
// c串
s = (char*)newsh+hdrlen;
//设置新的类型
s[-1] = type;
//设置新的sds长度
sdssetlen(s, len);
}
//设置sds可用内存为0的内存
sdssetalloc(s, len);
return s;
}
@ -389,13 +476,21 @@ sds sdsRemoveFreeSpace(sds s) {
* 3) The free buffer at the end if any.
* 4) The implicit null term.
*/
// 返回一个sds的总长度包括头二进制字符串分配的内存长度和'\0'
size_t sdsAllocSize(sds s) {
//sds分配的内存大小
size_t alloc = sdsalloc(s);
// sds类型结构占用的内存大小 + 可用内存空间 + 1
return sdsHdrSize(s[-1])+alloc+1;
}
/* Return the pointer of the actual SDS allocation (normally SDS strings
* are referenced by the start of the string buffer). */
/**
* sds的控制结构的起始地址
* @param s sds字符串
* @return
*/
void *sdsAllocPtr(sds s) {
return (void*) (s-sdsHdrSize(s[-1]));
}
@ -423,6 +518,11 @@ void *sdsAllocPtr(sds s) {
* ... check for nread <= 0 and handle it ...
* sdsIncrLen(s, nread);
*/
/**
* sds的已经使用的长度
* @param s
* @param incr
*/
void sdsIncrLen(sds s, ssize_t incr) {
unsigned char flags = s[-1];
size_t len;
@ -469,6 +569,12 @@ void sdsIncrLen(sds s, ssize_t incr) {
*
* if the specified length is smaller than the current length, no operation
* is performed. */
/**
* sds的已经使用长度增加到指定长度
* @param s
* @param len
* @return
*/
sds sdsgrowzero(sds s, size_t len) {
size_t curlen = sdslen(s);
@ -487,6 +593,13 @@ sds sdsgrowzero(sds s, size_t len) {
*
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
/**
* sds后面连接给定长度的二进制字符串
* @param s
* @param t
* @param len
* @return
*/
sds sdscatlen(sds s, const void *t, size_t len) {
size_t curlen = sdslen(s);
@ -502,6 +615,12 @@ sds sdscatlen(sds s, const void *t, size_t len) {
*
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
/**
* sds后面连接一个C字符串
* @param s
* @param t
* @return
*/
sds sdscat(sds s, const char *t) {
return sdscatlen(s, t, strlen(t));
}
@ -510,12 +629,25 @@ sds sdscat(sds s, const char *t) {
*
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
/**
* sds的已经使用的内存连接到另一个sds中
* @param s
* @param t
* @return
*/
sds sdscatsds(sds s, const sds t) {
return sdscatlen(s, t, sdslen(t));
}
/* Destructively modify the sds string 's' to hold the specified binary
* safe string pointed by 't' of length 'len' bytes. */
/**
* sds使
* @param s
* @param t
* @param len
* @return
*/
sds sdscpylen(sds s, const char *t, size_t len) {
if (sdsalloc(s) < len) {
s = sdsMakeRoomFor(s,len-sdslen(s));
@ -529,6 +661,12 @@ sds sdscpylen(sds s, const char *t, size_t len) {
/* Like sdscpylen() but 't' must be a null-termined string so that the length
* of the string is obtained with strlen(). */
/**
* C字符串复制到sds
* @param s
* @param t
* @return
*/
sds sdscpy(sds s, const char *t) {
return sdscpylen(s, t, strlen(t));
}
@ -539,6 +677,9 @@ sds sdscpy(sds s, const char *t) {
*
* The function returns the length of the null-terminated string
* representation stored at 's'. */
/**
* long long转换成C字符串格式
*/
#define SDS_LLSTR_SIZE 21
int sdsll2str(char *s, long long value) {
char *p, aux;
@ -570,7 +711,12 @@ int sdsll2str(char *s, long long value) {
}
return l;
}
/**
* unsigned long long C字符串格式
* @param s
* @param v
* @return
*/
/* Identical sdsll2str(), but for unsigned long long type. */
int sdsull2str(char *s, unsigned long long v) {
char *p, aux;
@ -604,13 +750,24 @@ int sdsull2str(char *s, unsigned long long v) {
*
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
/**
* 使long long制造一个sds
* @param value
* @return
*/
sds sdsfromlonglong(long long value) {
char buf[SDS_LLSTR_SIZE];
int len = sdsll2str(buf,value);
return sdsnewlen(buf,len);
}
/**
* sds后面
* @param s
* @param fmt
* @param ap
* @return
*/
/* Like sdscatprintf() but gets va_list instead of being variadic. */
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
va_list cpy;
@ -669,6 +826,13 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
*
* s = sdscatprintf(sdsempty(), "... your format ...", args);
*/
/**
* sdscatvprintf的包装
* @param s
* @param fmt
* @param ...
* @return
*/
sds sdscatprintf(sds s, const char *fmt, ...) {
va_list ap;
char *t;
@ -694,6 +858,13 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
* %% - Verbatim "%" character.
*/
/**
* sdscatvprintf功能一样使sprintf族函数
* @param s
* @param fmt
* @param ...
* @return
*/
sds sdscatfmt(sds s, char const *fmt, ...) {
size_t initlen = sdslen(s);
const char *f = fmt;
@ -802,6 +973,12 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
*
* Output will be just "HelloWorld".
*/
/**
* sds的头和尾去掉所有和给定字符一致的内容
* @param s
* @param cset
* @return
*/
sds sdstrim(sds s, const char *cset) {
char *start, *end, *sp, *ep;
size_t len;
@ -820,15 +997,25 @@ sds sdstrim(sds s, const char *cset) {
/* Changes the input string to be a subset of the original.
* It does not release the free space in the string, so a call to
* sdsRemoveFreeSpace may be wise after. */
/**
*
* @param s
* @param start
* @param len
*/
void sdssubstr(sds s, size_t start, size_t len) {
/* Clamp out of range input */
//获取sds长度
size_t oldlen = sdslen(s);
//如果起始点大于sds长度 则设置start = len = 0
if (start >= oldlen) start = len = 0;
//长度如果大于 sds长度-起始点 重新设置长度为 sds长度-起始点
if (len > oldlen-start) len = oldlen-start;
//将 s 的 N 个字节复制到 DEST保证重叠字符串的正确行为。
/* Move the data */
if (len) memmove(s, s+start, len);
s[len] = 0;
//给sds设置新的长度
sdssetlen(s,len);
}
@ -853,6 +1040,12 @@ void sdssubstr(sds s, size_t start, size_t len) {
* s = sdsnew("Hello World");
* sdsrange(s,1,-1); => "ello World"
*/
/**
* sds切片
* @param s sds字符串
* @param start
* @param end
*/
void sdsrange(sds s, ssize_t start, ssize_t end) {
size_t newlen, len = sdslen(s);
if (len == 0) return;
@ -863,14 +1056,20 @@ void sdsrange(sds s, ssize_t start, ssize_t end) {
newlen = (start > end) ? 0 : (end-start)+1;
sdssubstr(s, start, newlen);
}
/**
* sds的所有字母变成小写tolower
* @param s sds
*/
/* Apply tolower() to every character of the sds string 's'. */
void sdstolower(sds s) {
size_t len = sdslen(s), j;
for (j = 0; j < len; j++) s[j] = tolower(s[j]);
}
/**
* sds的所有字母变成大写toupper
* @param s sds
*/
/* Apply toupper() to every character of the sds string 's'. */
void sdstoupper(sds s) {
size_t len = sdslen(s), j;
@ -889,6 +1088,12 @@ void sdstoupper(sds s) {
* If two strings share exactly the same prefix, but one of the two has
* additional characters, the longer string is considered to be greater than
* the smaller one. */
/**
* sdsmemcmp
* @param s1
* @param s2
* @return
*/
int sdscmp(const sds s1, const sds s2) {
size_t l1, l2, minlen;
int cmp;
@ -917,6 +1122,15 @@ int sdscmp(const sds s1, const sds s2) {
* requires length arguments. sdssplit() is just the
* same function but for zero-terminated strings.
*/
/**
* sds指针数组使KMP优化
* @param s
* @param len
* @param sep
* @param seplen
* @param count
* @return
*/
sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count) {
int elements = 0, slots = 5;
long start = 0, j;
@ -966,7 +1180,11 @@ cleanup:
return NULL;
}
}
/**
* sdssplitlen产生的指针数组和其中的sds的内存
* @param tokens
* @param count
*/
/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
void sdsfreesplitres(sds *tokens, int count) {
if (!tokens) return;
@ -981,6 +1199,13 @@ void sdsfreesplitres(sds *tokens, int count) {
*
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
/**
*
* @param s
* @param p
* @param len
* @return
*/
sds sdscatrepr(sds s, const char *p, size_t len) {
s = sdscatlen(s,"\"",1);
while(len--) {
@ -1005,14 +1230,22 @@ sds sdscatrepr(sds s, const char *p, size_t len) {
}
return sdscatlen(s,"\"",1);
}
/**
* char c是否是十六进制数ASCII码判断的
* @param c
* @return
*/
/* Helper function for sdssplitargs() that returns non zero if 'c'
* is a valid hex digit. */
int is_hex_digit(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F');
}
/**
*
* @param c
* @return
*/
/* Helper function for sdssplitargs() that converts a hex digit into an
* integer from 0 to 15 */
int hex_digit_to_int(char c) {
@ -1056,6 +1289,12 @@ int hex_digit_to_int(char c) {
* quotes or closed quotes followed by non space characters
* as in: "foo"bar or "foo'
*/
/**
* sds指针数组使sds中sds指针数组和其元素个数
* @param line
* @param argc
* @return
*/
sds *sdssplitargs(const char *line, int *argc) {
const char *p = line;
char *current = NULL;
@ -1175,6 +1414,14 @@ err:
*
* The function returns the sds string pointer, that is always the same
* as the input pointer since no resize is needed. */
/**
* sds中出现在指定字符集中的字符用另一个字符集中的字符代替
* @param s
* @param from
* @param to
* @param setlen
* @return
*/
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
size_t j, i, l = sdslen(s);
@ -1191,6 +1438,13 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
/* Join an array of C strings using the specified separator (also a C string).
* Returns the result as an sds string. */
/**
* C字符串用提供的分割器连接起来sds
* @param argv
* @param argc
* @param sep
* @return
*/
sds sdsjoin(char **argv, int argc, char *sep) {
sds join = sdsempty();
int j;
@ -1201,7 +1455,14 @@ sds sdsjoin(char **argv, int argc, char *sep) {
}
return join;
}
/**
* sdsjoin类似sds
* @param argv
* @param argc
* @param sep
* @param seplen
* @return
*/
/* Like sdsjoin, but joins an array of SDS strings. */
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
sds join = sdsempty();
@ -1219,8 +1480,23 @@ sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
* the overhead of function calls. Here we define these wrappers only for
* the programs SDS is linked to, if they want to touch the SDS internals
* even if they use a different allocator. */
/**
*
* @param size
* @return
*/
void *sds_malloc(size_t size) { return s_malloc(size); }
/**
*
* @param ptr
* @param size
* @return
*/
void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); }
/**
*
* @param ptr
*/
void sds_free(void *ptr) { s_free(ptr); }
/* Perform expansion of a template string and return the result as a newly
@ -1229,6 +1505,13 @@ void sds_free(void *ptr) { s_free(ptr); }
* Template variables are specified using curly brackets, e.g. {variable}.
* An opening bracket can be quoted by repeating it twice.
*/
/**
* sds字符串模板
* @param template
* @param cb_func
* @param cb_arg
* @return
*/
sds sdstemplate(const char *template, sdstemplate_callback_t cb_func, void *cb_arg)
{
sds res = sdsempty();

View File

@ -140,7 +140,7 @@ static inline size_t sdslen(const sds s) {
}
return 0;
}
//sds可用长度
//sds可用内存大小
static inline size_t sdsavail(const sds s) {
//s[-1]的值是flags的值 要求编译器取消内存对齐优化按照实际的占用字节数进行对齐buf的前面是flags
unsigned char flags = s[-1];
@ -229,7 +229,7 @@ static inline void sdsinclen(sds s, size_t inc) {
}
}
/**
* = +
* sds = sds可用大小 + sds长
* @param s
* @return
*/
@ -252,7 +252,7 @@ static inline size_t sdsalloc(const sds s) {
return 0;
}
/**
*
*
* @param s
* @param newlen
*/

View File

@ -118,7 +118,11 @@ void *ztrymalloc_usable(size_t size, size_t *usable) {
return (char*)ptr+PREFIX_SIZE;
#endif
}
/**
*
* @param size
* @return
*/
/* Allocate memory or panic */
void *zmalloc(size_t size) {
void *ptr = ztrymalloc_usable(size, NULL);
@ -131,7 +135,12 @@ void *ztrymalloc(size_t size) {
void *ptr = ztrymalloc_usable(size, NULL);
return ptr;
}
/**
* NULL则分配内存失败 *usable
* @param size
* @param usable
* @return
*/
/* Allocate memory or panic.
* '*usable' is set to the usable size if non NULL. */
void *zmalloc_usable(size_t size, size_t *usable) {
@ -139,12 +148,7 @@ void *zmalloc_usable(size_t size, size_t *usable) {
if (!ptr) zmalloc_oom_handler(size);
return ptr;
}
/**
* NULL则分配内存失败 *usable
* @param size
* @param usable
* @return
*/
/* Allocation and free functions that bypass the thread cache
* and go straight to the allocator arena bins.
* Currently implemented only for jemalloc. Used for online defragmentation. */
@ -254,7 +258,12 @@ void *ztryrealloc_usable(void *ptr, size_t size, size_t *usable) {
return (char*)newptr+PREFIX_SIZE;
#endif
}
/**
* 0
* @param ptr
* @param size
* @return
*/
/* Reallocate memory and zero it or panic */
void *zrealloc(void *ptr, size_t size) {
ptr = ztryrealloc_usable(ptr, size, NULL);
@ -267,7 +276,13 @@ void *ztryrealloc(void *ptr, size_t size) {
ptr = ztryrealloc_usable(ptr, size, NULL);
return ptr;
}
/**
* NULL则内存分配失败
* @param ptr
* @param size
* @param usable
* @return
*/
/* Reallocate memory or panic.
* '*usable' is set to the usable size if non NULL. */
void *zrealloc_usable(void *ptr, size_t size, size_t *usable) {
@ -289,7 +304,10 @@ size_t zmalloc_usable_size(void *ptr) {
return zmalloc_size(ptr)-PREFIX_SIZE;
}
#endif
/**
*
* @param ptr
*/
void zfree(void *ptr) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;