Skip to content

Commit

Permalink
finish prev commit with snake_case fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
al1-ce committed Oct 17, 2024
1 parent 3a8cb95 commit 26e072e
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 108 deletions.
36 changes: 23 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ This library includes all (almost?) "aliases" to `core.stdc.*` modules in respec

# Custom modules
- [x] format (exists in C++20 specs, but my version currently is for emulating c's format function)
- [ ] conv (just your normal type conversion)
- [ ] conv (just your normal type conversion, right now contains only c++ "casts")

## On classes
D's keyword `new` can't be used with noGC and to "fix" that there's two functions: `_new` and `_free` in `clib.memory` which can be used to create classes with noGC.
Expand Down Expand Up @@ -84,7 +84,7 @@ class DClass {}
class DChild: DClass{}
DChild dprt;
if (typeid(dprt) != typeid(DClass)) printf("Not same\n");
if (typeid(DClass).isBaseOf(typeid(DChild))) printf("Is child\n");
if (typeid(DClass).is_base_of(typeid(DChild))) printf("Is child\n");
// Clib way:
Expand All @@ -100,38 +100,48 @@ class CChild: CClass{
CChild cprt;
if (_typeid(cprt) != _typeid!CClass) printf("Not same\n");
if (_typeid!CClass().isBaseOf(cprt)) printf("Is child\n");
if (_typeid!CClass().is_base_of(cprt)) printf("Is child\n");
```

`clib.typeinfo.reinterpret_cast` can be used to work around [known bug](https://issues.dlang.org/show_bug.cgi?id=21690).
```d
import core.stdc.stdio;
import clib.typecast;
import clib.stdio;
import clib.typeinfo;
import clib.memory;
import clib.conv;
extern(C++) class ICpp: CppObject {
void baseFunc() @nogc nothrow { printf("ICpp func\n"); }
void base_func() @nogc nothrow { printf("ICpp func\n"); }
}
extern(C++) class CppClass: ICpp {
mixin RTTI!ICpp;
override void baseFunc() @nogc nothrow { printf("CppClass func\n"); }
override void base_func() @nogc nothrow { printf("CppClass func\n"); }
}
extern(C) int main() @nogc nothrow {
CppClass c = _new!CppClass();
void testBaseFunc(ICpp base) {
base.baseFunc();
reinterpret_cast!ICpp(base).baseFunc(); // doesn't matter as it's already ICpp
void test_base_func(ICpp base) {
base.base_func();
reinterpret_cast!ICpp(base).base_func(); // doesn't matter as it's already ICpp
}
testBaseFunc(c); // will case segfault!!!
testBaseFunc(reinterpret_cast!ICpp(c)); // must be a cast
reinterpret_cast!ICpp(c).testBaseFunc(); // or treat it as member
test_base_func(c); // will case segfault!!!
test_base_func(reinterpret_cast!ICpp(c)); // must be a cast
reinterpret_cast!ICpp(c).test_base_func(); // or treat it as member
}
```

## Disable GC

Before `main` function or entrance point put:

```d
import clib.memory: DISABLE_GC;
mixin DISABLE_GC;
```

## Development
- [dmd / ldc / gdc](https://dlang.org/) - D compiler
- [dub](https://code.dlang.org/) - D package manager
Expand Down
39 changes: 39 additions & 0 deletions src/clib/conv.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module clib.conv;
// TODO: add separate cast versions for C++ linkage and D classes

/// Interprets F as T (dangerous, use mainly as workaround to bug 21690)
T reinterpret_cast(T, F)(F t) @nogc nothrow {
return ( cast(T) cast(void*) t );
}

/// Downcasts F to T (CAN RETURN NULL IF UNABLE TO DOWNCAST)
T dynamic_cast(T, F)(F t) @nogc nothrow if (IS_CLASS!T && IS_CLASS!F) {
if (_typeid!(F)().is_base_of!(T)()) {
return ( cast(T) cast(void*) t );
} else {
return null;
}
}

/// Downcasts F to T or converts scalar types (CAN RETURN NULL IF UNABLE TO DOWNCAST)
T static_cast(T, F)(F t) @nogc nothrow
if ((IS_CLASS!T && IS_CLASS!F) || (IS_SCALAR!T && IS_SCALAR!F)) {
if (IS_SCALAR_TYPE!T) {
return cast(T) t;
} else {
return dynamic_cast!(T, F)(t);
}
}

/// Performs basic type casting
T const_cast(T, F)(F t) @nogc nothrow {
return cast(T) t;
}

private enum bool IS_SCALAR(T) = __traits(isScalar, T) && is(T : real);

private enum bool IS_CLASS(T) =
(is(T == U*, U) && (is(T == class) || is(T == interface))) ||
(is(T == class) || is(T == interface));


2 changes: 1 addition & 1 deletion src/clib/format.d
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ scope cstring format(A...)(const(char)[] fmt, A args) @nogc nothrow {
char* buffer = cast(char*) malloc(len);
snprintf(buffer, len, fmt.ptr, args);
cstring str;
str.assignPointer(buffer, len);
str.assign_pointer(buffer, len);
return str;
}

Expand Down
4 changes: 4 additions & 0 deletions src/clib/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ module clib.memory;

import clib.stdlib: malloc, realloc, free;

mixin template DISABLE_GC() {
extern(C) __gshared string[] rt_options = [ "gcopt=disable:1" ];
}

/++
Used to allocate/deallocate memory for classes
Expand Down
1 change: 1 addition & 0 deletions src/clib/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public import
clib.assert_,
clib.complex,
clib.ctype,
clib.conv,
clib.errno,
clib.exception,
clib.fenv,
Expand Down
86 changes: 25 additions & 61 deletions src/clib/typeinfo.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ version(CLIB_USE_TYPEINFO):

import clib.string: strcmp;
import clib.traits;
import clib.conv;

import clib.memory;

Expand Down Expand Up @@ -64,11 +65,11 @@ struct type_info {
/// Fully qualified type name
const char* name = "\0".ptr;
/// Is type a pointer
const bool isPointer = false;
const bool IS_POINTER = false;
/// Is type a function
const bool isFunction = false;
private const char[] _strName;
private bool _isACppObject = false;
const bool is_function = false;
private const char[] _str_name;
private bool _is_a_cpp_object = false;

/// Returns fully qualified type name
const(char*) toString() const { return name; }
Expand All @@ -95,18 +96,18 @@ struct type_info {
}

/// Is T a child of type_info owner
bool isBaseOf(T)(T t) @nogc nothrow {
return isBaseOf!T;
bool is_base_of(T)(T t) @nogc nothrow {
return is_base_of!T;
}

/// Ditto
bool isBaseOf(T)() @nogc nothrow {
if (isPointer || isFunction) return false;
bool is_base_of(T)() @nogc nothrow {
if (IS_POINTER || is_function) return false;
import clib.string: strlen, memcmp;
if (!isSubclassOfCppObject!T) return false;
if (_isACppObject) return true;
if (!IS_SUBCLASS_OF_CPP_OBJECT!T) return false;
if (_is_a_cpp_object) return true;
char[200] s = ' ';
char[] t = cast(char[]) _strName;
char[] t = cast(char[]) _str_name;

s[0..2] = cast(char[]) "__";

Expand All @@ -131,45 +132,45 @@ struct type_info {
}

/// Queries information about type
type_info _typeid(T)(T t) @nogc nothrow if (isSuitableForTypeID!T) {
type_info _typeid(T)(T t) @nogc nothrow if (IS_SUITABLE_FOR_TYPEID!T) {
return _typeid!T();
}

/// Ditto
type_info _typeid(T)() @nogc nothrow if (isSuitableForTypeID!T) {
type_info _typeid(T)() @nogc nothrow if (IS_SUITABLE_FOR_TYPEID!T) {
type_info t = {
cast(const(char*)) __traits(fullyQualifiedName, Unqual!T).ptr,
isPointer!T,
isFunctionPointer!T || isDelegate!T,
cast(const(char[])) __traits(fullyQualifiedName, Unqual!T),
cast(const(char*)) __traits(fullyQualifiedName, UNQUAL!T).ptr,
IS_POINTER!T,
IS_FUNCTION_POINTER!T || IS_DELEGATE!T,
cast(const(char[])) __traits(fullyQualifiedName, UNQUAL!T),
is(T == CppObject)
};

return t;
}

private bool isSuitableForTypeID(T)() @nogc nothrow {
private bool IS_SUITABLE_FOR_TYPEID(T)() @nogc nothrow {
static if (is(T == interface)) return true;
const bool isPtr = isAnyPointerType!T;
const bool isPtr = IS_ANY_POINTER_TYPE!T;
static if (!isPtr) {
return isSubclassOfCppObject!T;
return IS_SUBCLASS_OF_CPP_OBJECT!T;
} else {
return true;
}
}

private bool isSubclassOfCppObject(T)() @nogc nothrow if (!isAnyPointerType!T) {
private bool IS_SUBCLASS_OF_CPP_OBJECT(T)() @nogc nothrow if (!IS_ANY_POINTER_TYPE!T) {
bool isCpp = __traits(getLinkage, T) == "C++";
bool isObj = __traits(hasMember, T, "__clib_cpp_object_identifier");
return isCpp && isObj;
}

private bool isAnyPointerType(T)() @nogc nothrow {
return isPointer!T || isFunctionPointer!T || isDelegate!T;
private bool IS_ANY_POINTER_TYPE(T)() @nogc nothrow {
return IS_POINTER!T || IS_FUNCTION_POINTER!T || IS_DELEGATE!T;
}

/// Injects RunTime Type Information (allows type_info to see inheritance)
mixin template RTTI(T) if ((isSubclassOfCppObject!T || is(T == interface)) && !is(T == CppObject)) {
mixin template RTTI(T) if ((IS_SUBCLASS_OF_CPP_OBJECT!T || is(T == interface)) && !is(T == CppObject)) {
mixin( __cpp_class_inheritance_generator!T() );
}

Expand All @@ -193,40 +194,3 @@ char[200] __cpp_class_inheritance_generator(T)() {
return s;
}

// TODO: add separate cast versions for C++ linkage and D classes

/// Interprets F as T (dangerous, use mainly as workaround to bug 21690)
T reinterpret_cast(T, F)(F t) @nogc nothrow {
return ( cast(T) cast(void*) t );
}

/// Downcasts F to T (CAN RETURN NULL IF UNABLE TO DOWNCAST)
T dynamic_cast(T, F)(F t) @nogc nothrow if (isClass!T && isClass!F) {
if (_typeid!(F)().isBaseOf!(T)()) {
return ( cast(T) cast(void*) t );
} else {
return null;
}
}

/// Downcasts F to T or converts scalar types (CAN RETURN NULL IF UNABLE TO DOWNCAST)
T static_cast(T, F)(F t) @nogc nothrow
if ((isClass!T && isClass!F) || (isScalar!T && isScalar!F)) {
if (isScalarType!T) {
return cast(T) t;
} else {
return dynamic_cast!(T, F)(t);
}
}

/// Performs basic type casting
T const_cast(T, F)(F t) @nogc nothrow {
return cast(T) t;
}

private enum bool isScalar(T) = __traits(isScalar, T) && is(T : real);

private enum bool isClass(T) =
(is(T == U*, U) && (is(T == class) || is(T == interface))) ||
(is(T == class) || is(T == interface));

Loading

0 comments on commit 26e072e

Please sign in to comment.