Last active
August 16, 2019 08:47
-
-
Save blackball/e731b075314cb2775f870b70e0fe5875 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// For modules that we care about the memory safety, we should never allow user | |
/// to have a way to access the memory directly. In this case, handle will be a | |
/// more useful tool. But in order to use handle safely, some tricks required. | |
/// Here I try to make an example of using handle to design simple API. | |
/// NOTE: for now we assume all codes will only be ran in single-thread, MT | |
// could be enabled easily though. | |
#include <stdio.h> | |
#include <stdlib.h> | |
struct object | |
{ | |
int uid, gid; | |
}; | |
int object_isvalid(const struct object obj); | |
// allocate an object | |
struct object object_create(); | |
// deallocate an object | |
void object_destroy(const struct object obj); | |
// use the allocated object | |
void object_use(const struct object obj); | |
/// the implementation | |
enum objectimplstatus | |
{ | |
objectimplstatus_free = 0, | |
objectimplstatus_inuse, | |
}; | |
struct objectimpl | |
{ | |
int status; | |
int gid; // generation id used to avoid use-after-free issue | |
int val; | |
}; | |
#define OBJECT_INVALID_ID 0 | |
#define OBJECT_MAX_NUM 32 | |
static struct | |
{ | |
struct objectimpl impls[OBJECT_MAX_NUM+1]; // the valid slot is from 1 to MAX_NUM | |
} sg_system; | |
// here we are relying on the *static* to initialize system, | |
// we could make impls to be dynamic, Implement the dynamic version | |
// in C is little bit lengthy, but C++ RAII feature could | |
// make it easier. | |
static struct objectimpl* | |
system_get(const struct object obj) | |
{ | |
return &(sg_system.impls[obj.uid]); | |
} | |
static inline int | |
system_size() | |
{ | |
return OBJECT_MAX_NUM; | |
} | |
static inline int | |
system_isvalid(const struct object obj) | |
{ | |
return obj.uid > 0 && obj.uid <= system_size() && (sg_system.impls[obj.uid].gid == obj.gid); | |
} | |
static struct object | |
system_allocate() | |
{ | |
struct object obj; | |
int i = OBJECT_MAX_NUM; | |
for (; i > 0; --i) { | |
if (sg_system.impls[i].status == objectimplstatus_free) { | |
break; | |
} | |
} | |
sg_system.impls[i].status = objectimplstatus_inuse; | |
obj.uid = i; | |
obj.gid = sg_system.impls[i].gid; | |
return obj; | |
} | |
static void | |
system_deallocate(const struct object obj) | |
{ | |
if (system_isvalid(obj)) { | |
sg_system.impls[obj.uid].status = objectimplstatus_free; | |
sg_system.impls[obj.uid].gid++; | |
} | |
else { | |
puts("Try to deallocate an invalid object!"); | |
} | |
} | |
/// Below is the external API implementation | |
int | |
object_isvalid(const struct object obj) | |
{ | |
return system_isvalid(obj); | |
} | |
struct object | |
object_create() | |
{ | |
return system_allocate(); | |
} | |
void | |
object_destroy(const struct object obj) | |
{ | |
system_deallocate(obj); | |
} | |
void | |
object_use(const struct object obj) | |
{ | |
if (object_isvalid(obj)) { | |
struct objectimpl *pimp = system_get(obj); | |
pimp->val += 3; | |
printf("%d\n", pimp->val); | |
} | |
} | |
int main() | |
{ | |
struct object obj = object_create(); | |
object_use(obj); | |
object_use(obj); | |
object_destroy(obj); | |
object_destroy(obj); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment