Platform Dependent Layer Platform-dependent code layer that contains all platform-specific implementations. This layer handles all platform-specific code and enables the rest of the system to operate platform-independently. Conditional compilation (#IF, #ELSE, etc.) is only permitted in this module.
더 자세히 ...
네임스페이스 | |
| namespace | by::platformAPI |
| Platform-independent API wrapper for OS-specific operations | |
클래스 | |
| class | by::fsystem |
| Cross-platform filesystem utilities for recursive file traversal 더 자세히 ... | |
| class | by::buildFeature |
| Provides build-time information and feature detection 더 자세히 ... | |
| struct | by::buildFeature::date |
| Build date information 더 자세히 ... | |
| struct | by::buildFeature::time |
| Build time information 더 자세히 ... | |
| struct | by::buildFeature::version |
| Version information 더 자세히 ... | |
| struct | by::buildFeature::platform |
| Platform information 더 자세히 ... | |
| struct | by::buildFeature::config |
| Build configuration information 더 자세히 ... | |
| class | by::cpIter |
| Codepoint-based string iterator 더 자세히 ... | |
| class | by::dlib |
| Dynamic library loading and management class 더 자세히 ... | |
| class | by::dumpable |
| Interface for objects that can dump their state 더 자세히 ... | |
| class | by::end |
| Deferred execution utility similar to defer keyword in other languages 더 자세히 ... | |
| class | by::errLv |
| Error level definitions and utilities 더 자세히 ... | |
| class | by::errorable |
| Interface for objects that can report errors 더 자세히 ... | |
| class | by::line |
| Manages hierarchical depth visualization for logging and tracing. 더 자세히 ... | |
| class | by::tmay< T > |
| Optional value wrapper for error indication without exceptions 더 자세히 ... | |
| class | by::tmedium< T > |
| Medium class used exclusively in the OR macro for safe reference handling 더 자세히 ... | |
| class | by::tres< T, R > |
| Template result container with typed error information 더 자세히 ... | |
| struct | by::typeTrait< T > |
| Type trait utilities for template metaprogramming 더 자세히 ... | |
| struct | by::Initiator |
| Utility for executing code before main() function 더 자세히 ... | |
매크로 | |
| #define | _ON_EACH_DECL(cmd) __BY__DECL_##cmd |
| byeol universal macro | |
| #define | __BY__DECL_ME_1(ME) BY_ME_1(ME) |
| byeolMeta macro's sub-commands, ME | |
| #define | BY_DEF_ME_2(ME, SUPER) __BY__DECL_DEF_ME_2(ME, SUPER) |
| byeolMeta macro's sub-commands, DEF_ME | |
| #define | __OR_DO__(_expr_) |
| OR macro | |
| #define | BY_OVERLOAD(NAME, ...) BY_CONCAT(NAME##_, __OVERLOAD_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__) |
| Macro Overloding: | |
| #define | BY_PAIR_1(x) x |
| Funnel | |
| #define | BY_SIDE_FUNC(...) BY_OVERLOAD(BY_SIDE_FUNC, __VA_ARGS__) |
| Side function macros for safe pointer operations | |
| #define | TO(fn) |
| #define | __WHEN_OBJECT__ __indep_when__ |
| Early-return pattern macro for exception handling | |
Platform Dependent Layer Platform-dependent code layer that contains all platform-specific implementations. This layer handles all platform-specific code and enables the rest of the system to operate platform-independently. Conditional compilation (#IF, #ELSE, etc.) is only permitted in this module.
| #define __BY__DECL_ME_1 | ( | ME | ) | BY_ME_1(ME) |
byeolMeta macro's sub-commands, ME
it defines 2 typedefs, me and super. me is same type to typeof(this) class in c++. and super is literally superclass of me. those typedefs are also available in byeol language.
This is part of an effort to make the environment of the byeol language and the C++ environment as consistent as possible.
| #define __OR_DO__ | ( | _expr_ | ) |
OR macro
It enables return ?:, a type of safe navigation in modern languages, in C++. prerequisites: OR macro is based on WHEN macro. Before learning about OR, you need to know WHEN first.
usage: OR macro is used like this: <expr-evalution-as-pointer> OR.<when-expr> in this case, expr-evaluation-as-pointer must evaluate to a pointer type of a certain type. if not, a compilation error occurs. an expression using the WHEN macro is placed after OR, and is executed instead if the previous pointer was nullptr. if the pointer was not nullptr, it is returned as a reference. as a result, using the OR macro, you can safely perform nullcheck and handle non-null types.
the WHEN macro provides various methods in addition to simply returning an error. please check it if want to know more.
FAQ: Q. I want to use OR and also do casting as (T&). A. since OR's return type is reference, you may simply write some code like below.
the reason is that, as mentioned earlier, the left side of OR must always be a pointer. therefore, it should not be (T&) but (T*). this is correct codes.
Q. Can I use OR after return? A. OR was created based on the precondition that it would be used when defining a variable. It cannot be used with the return keyword.
Q. I used OR macro with auto& and got Non-const lvalue reference to... error. my code is like below,
A. don't use auto keyword. the actual return type of OR macro could be tmedium<T> or tstr or tweak. it differs in context which you're using. it was specified in each operand class file, for instance, 'tstr.hpp'. and if you used OR macro which returns tmedium, it is implicitly returned as T& through this class. therefore, unless you have a special situation where you want to use tmedium, specify the type directly instead of auto.
Q. I used OR in a function whose return type is tmay and initialized it with a T&& variable, but the value is strange.
A. TLDR; take rvalue with type tmay<A>&& just like rvalue reference to return type of the function.
foo() returns tmay by value. If you receive something returned by value as an rvalue reference, its life would be extended, but in this case, since it is not received as tmay, the value inside it is taken out and returned, so the tmay temporary object does not extend its life and starts to die immediately. as a result, a garbage value is bound to A&& a.
| #define __WHEN_OBJECT__ __indep_when__ |
Early-return pattern macro for exception handling
The byeol project actively applies the early-return pattern throughout. This helps reduce code depth, improve code flow clarity, and handle exceptional situations immediately. However, traditional if statements make it difficult to distinguish between normal branching logic and early-return exception handling.
Consider this traditional early-return code:
The WHEN macro solves this by explicitly marking early-return cases. It is used exclusively for early-return patterns. Additionally, since over 90% of early-returns involve logging an error and returning an error value, WHEN supports chaining to express both operations in a single line.
The same code becomes much clearer with WHEN:
Now the purpose of each if is clear, and exception handling is visually distinct from normal branching logic.
__WHEN_OBJECT__ in each layer. | #define _ON_EACH_DECL | ( | cmd | ) | __BY__DECL_##cmd |
byeol universal macro
This reduces the possibility of macro conflicts between different libraries and makes macro writing easier. and this is generalized API used to describe the metadata of class in byeol. BY can be used to define detailed metadata about a class by chaining sub-command sets. these sub-commands are macros available only inside of BY.
for instance,
Each command preceding BY is prefixed with the __BY__DECL_ prefix. The following commands can be used within the BY macro: CLASS: Injects metadata for a concrete class. VISIT: Makes the class visitor-friendly. ME: Adds typedefs named super and me. DEF_ME: Same as ME, but used in the implementation file. ADT: Injects metadata for an abstract class. CLONE: Adds a virtual copy constructor.
| #define BY_DEF_ME_2 | ( | ME, | |
| SUPER ) __BY__DECL_DEF_ME_2(ME, SUPER) |
byeolMeta macro's sub-commands, DEF_ME
Similar to ME, this macro adds typedefs called me and super to the scope of the current compilation unit.
This macro was added for use when writing implementation files. Because the ME sub-command adds typedefs to the class scope, it's not available for you to access them outside of member fuctions when writing implementation file.
let me give you example:
| #define BY_OVERLOAD | ( | NAME, | |
| ... ) BY_CONCAT(NAME##_, __OVERLOAD_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__) |
Macro Overloding:
by count of given arguments, let compiler determine which macro should works. original source code from BuvinJ at https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
usage:
expected output should be, 10, 8, 100.
| #define BY_PAIR_1 | ( | x | ) | x |
Funnel
This macro mostly used to put in arguments to macro behind macro. Why does we need this?:
But, if you put class template as macro argument, expanding macro gets messed up. My_2(template<int, float>, template<A, B>) // in fact, preprocessor thought we passed 4 arguments, not 2.
Then, Use Funnel macro instead:
| #define BY_SIDE_FUNC | ( | ... | ) | BY_OVERLOAD(BY_SIDE_FUNC, __VA_ARGS__) |
Side function macros for safe pointer operations
Side Func is a term I coined. It refers to an overloaded function added for the convenience of the original function. For example:
This macro makes it easy to create side functions like the one above.
| #define TO | ( | fn | ) |
@breif safe navigation feature of c++
TO supports the safe navigation features of modern languages very intuitively and naturally. the basic usage is <expression> TO(yourAccessor()). let's explain with an example first before explain further.
usage: let's assume that we have following classes.
and what if there are funcs utilize above structs. in language spec of c++, there is no sort of safe navigation thing, so we've to do like this.
of course, this example illustrates a rather extreme train wreck pattern, and is a design that should be avoided, but situations where you need to access a pointer to a certain number of pointers occur frequently, and if you don't always check in advance whether the pointer is valid every time you dereference it, UB will occur.
to be:
with safe navigation, whether you will receive nullptr or not is
determined after the dereference chain of all pointers is finished. so the resulting code can become very concise.
the previously mentioned <expression> does not simply mean pointers and references, but also includes classes that satisfy the following conditions.
a. a class that defines operator->().
b. a class that defines operator*().
c. a class that defines operator bool().
you may have noticed that the classes that satisfy the above conditions
are usually smart pointers like unique_ptr. the byeol repository provides separate smart pointers and classes that replace std::optional<T> for API consistency and safe type checking. e.g. tstr<T>, tweak<T>, binder, tmay<T>, tres<T> are included here.
the TO() macro is designed to work properly even if the return value of
the function is a value or reference to the above class. it works even if it exists in the middle of safe navigation chain. for example,
@code
struct Resource {
Pallete* getPallete(); // this can return nullptr.
};
struct Pallete {
Canvas& getCanvas(); // this *never* returns nullptr.
};
struct Canvas {
tstr<Brush> getBrush(int type); // this is not pointer, but
pointer-like-variable.
};
int getBrushColorCode(Resource r) {
// however you can do exactly same like above example.
int* code = r TO(getPallete()) TO(getCanvas())
TO(getBrush(BrushType.SYSTEM)) TO(getColorCode())
// but you may notice that you don't have to put `TO` for
reference type. so, int* code = r TO(getPallete().getCanvas()) TO(getBrush(BrushType.SYSTEM)) TO(getColorCode());
if(!code) return -1; return code; }
3. don't recommend you to put a reference in `TO()` references are always non-null, so you can access them directly. 4. it is not recommended for any function to return a pointer type to a pointer-like-variable. pointer-like-variable is a sufficiently lightweight class. You canreturn it by value, or if you don't like that, return it by reference.
5. it goes very well with OR macro. please check the usage of OR macro in advance. If you also use WHENmacro, the code will become way more concise.
@code
int getBrushColorMode(Resource r) {
// this uses OR macro. so final type of the chain is `int&`.
// but `int&` can be copied into new variable `int`.
int code = r TO(getPallete())
TO(getCanvas().getBrush(BrushType.SYSTEM)) TO(getColorCode()) OR.err("code is
null").ret(-1) return code; }