https://github.com/aryan-programmer/universal-cpp
Universal C++ language extensions
https://github.com/aryan-programmer/universal-cpp
boost boost-libraries cpp cpp-lib cpp-library cpp17
Last synced: 6 months ago
JSON representation
Universal C++ language extensions
- Host: GitHub
- URL: https://github.com/aryan-programmer/universal-cpp
- Owner: aryan-programmer
- License: other
- Created: 2019-02-13T16:45:00.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2019-10-11T05:25:03.000Z (about 6 years ago)
- Last Synced: 2025-03-06T18:49:46.075Z (10 months ago)
- Topics: boost, boost-libraries, cpp, cpp-lib, cpp-library, cpp17
- Language: C++
- Homepage:
- Size: 705 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README

# UC++(Universal C++)
[TOC]
## × To implement || √ Implemented Features ← From Languages
### √ Garbage Collection ← Objective-C
Like Objective-C, UC++ support s GC, but only ARC (Automatic Reference Counting) style GC is supported, like in Objective-C where ARC is the recommended method.
### √ Reflection ← ~~Most~~ ***All*** languages with automatic garbage collection.
Use `UC::P_Any` variables and `UC::Object::Call` as:
```C++
?variable?->Call(?function-name?, {?args?})
```
or use UCC as:
```C++
UCC(?variable?, ?function-name?, {?args?})
```
to call methods using reflection. And use
```C++
static UC::Object::CreateInstance
```
to create instances of UCInterfaces as
```C++
UC::Object::CreateInstance(?class-name?, {?args?})
```
### √ Dynamic Typing ← Python
Use `UC::P_Any` variables and `UC::Object::Call` as:
```C++
?variable?->Call(?function-name?, {?args?})
```
or use UCC as:
```C++
UCC(?variable?, ?function-name?, {?args?})
```
to call methods using ***Dynamic Typing***. Yes, the methods to use for reflection and dynamic typing are the same.
For casting to higher types use
```C++
UC::ObjCast
```
as
```C++
UC::ObjCast(?variable?)
```
### √ Delegates ← C#
Delegates are from C#, but they aren't called delegates, they're called **_Functors_**.
Functor = **_Func_**tion + Opera**_tor_**
There are 3 core things to 'delegates' or functors
1. `UC::Function`
This template interface is abstract, it isn't directly instantiated, `UC::MakeFunc` is used for instantiating instances of this interface.
To call the stored function call `?functor?->Eval(?parameters?...)` with the designated ?parameters?...
2. Function type aliases and how to use them
They are defined as aliases for **_function types_**, not **_functor types_**. Define one as
```C++
typedef ?return-type? ?name?(?parameter-types?...)
```
Where ?name? & ?return-type? refer to the name of the alias & return type respectively, and ?parameter-types...? refers to 0 or more parameters.
To get a `UC::Function` from the alias use:
```C++
UC::FuncFrom
```
To get a `UC::Event` from the alias use:
```C++
UC::EventFrom
```
3. `UC::MakeFunc(TRealFunction&& func)`
Use this function as
```C++
UC::MakeFunc(?function/function-object/lambda/closure to-make-from?)
```
Where ?function-type? refers to the type of the function it can be `UC::Function` or a Function type alias. ?function/function-object/lambda/closure to-make-from? refers to exactly what the name says.
### √ Events ← Qt
Events are technically from C#. However they are also implemented in Qt (& Boost), but there they are called as signals and the functions which register to them are called slots. In C#, signals and slots are referred to as events and delegates. In UC++, signals and slots are referred to as events and functors (would you rather prefer "Group of UC++ GC pointer to function object" and "UC++ GC pointer to function object").
The template parameters for an event are the same as a functor `UC::Event`.
To create an event use `?event-type::Make()?` and assign it to a variable to class field.
To add a function, function-object, lambda or closure use `?event?->Add(?function/function-object/lambda/closure to-add?)`. To add a `UC::Function` use `?event?->AddF(?functor?)`. The return value of these functions is the id of the functor added, hold onto it if you want to erase the functor later.
To remove a functor using it's id use `?event?->Remove(?id?)`.
To invoke the event use `?event?->Eval(?parameters?...)` with the designated ?parameters?.... If the functor returns a value then `Eval` returns the return value of the last function, if there are no functors added then an error of type `UC::NoFunctorsAddedToEvent_Exception`, with the message
```C++
"UC::Event has no added functors that can return a value that can be returned."
```
If you want to get the return value of all the functions in a `UC::NatVector` use `?event?->EvalAll(?parameters?...)` with the designated ?parameters?.... Obviously, if the functors return `void` then `EvalAll` will not return a `UC::NatVector`. In reality, `EvalAll` will call all the functions and return `void`. If there are no functors added then the returned vector will have size `0`.
An event is a functor, i.e. you can chain events, i.e. subscribe an event to an event.
### √ Singleton ← Kotlin
The singleton pattern comes inbuilt with Kotlin, UC++ also provides an inbuilt singleton pattern.
For more information look to the documentation on the macro UC_IsSingleton.
### √ Generators ← C#
From [Wikipedia:Generator (computer programming)](https://en.wikipedia.org/wiki/Generator_(computer_programming))
> In computer science, a generator is a special routine that can be used to control the iteration behaviour of a loop. In fact, all generators are iterators. A generator is very similar to a function that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator yields the values one at a time, which requires less memory and allows the caller to get started processing the first few values immediately. In short, a generator looks like a function but behaves like an iterator.
The generators in UC++ do fulfil the above requirements but UC++ generators can do more, much. Look to the documentation for more info.
### √ Coroutines ← Unity
A similar system to the one provided by Unity by UC++, though there are some differences.
Look to the documentation for more info.
### √ Multiple Class Inheritance ← C++
From C++!!
### √ Block Structured Programming ← Swift
Already in C++.
# [Documentation](./DOCUMENTATION.md)
# Conversion, Macro substitution
The pre-macro substitution state:
```C++
//Empty.hpp
struct NEmpty
{
void NativeBaseFunction( );
};
UCInterface( Empty ,
UC_WhereTypenameIsRealName ,
UC_InheritsUCClasses( UC::Object ) ,
UC_InheritsNativeClasses( NEmpty )
)
UC_HasExplicitCtors( Empty , UC_AlsoHasEmptyMaker , ( _1 ) );
UC_HasMethods(
( Do ) ,
( Do , ( _1 ) ) ,
( Do , ( _1 , _2 ) )
);
void NativeFunction( );
UCEndInterface;
```
```C++
//Empty.cpp
#include
#include "Empty.hpp"
using namespace std;
UCRegister( Empty );
UCCtor( Empty::Empty )
{
cout << "0 parameters for " __FUNCTION__ << endl;
}
UCCtor( Empty::Empty , ( _1 ) )
{
cout << "1 parameter for " __FUNCTION__ << endl;
}
UCMethod( Empty::Do )
{
cout << "0 parameters for " __FUNCTION__ << endl;
return nullptr;
}
UCMethod( Empty::Do , ( _1 ) )
{
cout << "1 parameter for " __FUNCTION__ << endl;
return nullptr;
}
UCMethod( Empty::Do , ( _1 , _2 ) )
{
cout << "2 parameter for " __FUNCTION__ << endl;
return nullptr;
}
void Empty::NativeFunction( ) { std::cout << "From native function:" __FUNCTION__ << std::endl; }
void NEmpty::NativeBaseFunction( ) { std::cout << "From native function in base:" __FUNCTION__ << std::endl; }
```
The post-macro substitution state:
```C++
//Empty.hpp
struct NEmpty
{
void NativeBaseFunction( );
};
struct Empty : UC::Object , NEmpty , ::UC::EnableGCPtrFromMe
{
using base0 = UC::Object;
using nbase0 = NEmpty;
using self = Empty;
using pself = ::UC::GCP;
using wself = ::UC::WeakPtr;
using EGCPFM = ::UC::EnableGCPtrFromMe;
protected:
auto callImplUpChain( const ::UC::NatString& fname , const ::UC::NatODeque& args ) -> ::UC::P_Any
{
try
{
auto res0 = base0::callImpl( fname , args );
if ( res0 ) return res0;
}
catch ( const ::UC::NoSuchFunction_Exception& ) { };
throw ::UC::NoSuchConstructor_Exception(::UC::ConcatNatStrings(
::UC::NatString( "No function for type \"" "Empty" "\" with name \"" ) ,
fname , "\" that takes in " , std::to_string( args.size( ) ) ,
" parameters." ) );
}
private:
struct __classRegisterer
{
__classRegisterer( )
{::UC::Object::addConstructor( "Empty" , &self::make_reflective );}
};
static __classRegisterer __classRegistererInstance;
public:
static const ::UC::NatString& SGetTypeName( )
{
static auto nm = ::UC::NatString( "Empty" );
return nm;
}
virtual const ::UC::NatString& GetTypeName( ) const override{return SGetTypeName( );}
templatestatic ::UC::GCP Make( Args&&... args )
{return ::UC::GCP( new self( std::forward( args )... ) );}
protected:
protected:
Empty( );
Empty( ::UC::P_Any _1 );
public:
static ::UC::P_Any make_reflective( const ::UC::NatODeque& args )
{
switch ( args.size( ) )
{
case 0:return ::UC::GCP( new self( ) );
case 1: return ::UC::GCP( new self( args[ 0 ] ) );
default: throw ::UC::NoSuchConstructor_Exception(
::UC::ConcatNatStrings(::UC::NatString( "No constructor for type \"" ) ,
SGetTypeName( ) , "\" that takes in " , std::to_string( args.size( ) ) ,
" parameters." ) );
}
};
public:
virtual auto Do( ) -> ::UC::P_Any;
virtual auto Do( ::UC::P_Any _1 ) -> ::UC::P_Any;
virtual auto Do( ::UC::P_Any _1 , ::UC::P_Any _2 ) -> ::UC::P_Any;
protected:
auto callImpl( const ::UC::NatString& fname , const ::UC::NatODeque& args ) -> ::UC::P_Any
{
const auto& argsLen = args.size( );
if ( fname == "Do" && argsLen == 0 ) { return this->Do( ); }
if ( fname == "Do" && argsLen == 1 ) { return this->Do( args[ 0 ] ); }
if ( fname == "Do" && argsLen == 2 ) { return this->Do( args[ 0 ] , args[ 1 ] ); }
return callImplUpChain( fname , args );
}
public:
virtual ::UC::P_Any Call( const ::UC::NatString& fname , const ::UC::NatODeque& args ) override {return callImpl( fname , args );};
void NativeFunction( );
};
```
```C++
//Empty.cpp
#include
#include "Empty.hpp"
using namespace std;
Empty::__classRegisterer Empty::__classRegistererInstance {};
Empty::Empty( )
{
cout << "0 parameters for " __FUNCTION__ << endl;
}
Empty::Empty( ::UC::P_Any _1 )
{
cout << "1 parameter for " __FUNCTION__ << endl;
}
auto Empty::Do( ) -> ::UC::P_Any
{
cout << "0 parameters for " __FUNCTION__ << endl;
return nullptr;
}
auto Empty::Do( ::UC::P_Any _1 ) -> ::UC::P_Any
{
cout << "1 parameter for " __FUNCTION__ << endl;
return nullptr;
}
auto Empty::Do( ::UC::P_Any _1 , ::UC::P_Any _2 ) -> ::UC::P_Any
{
cout << "2 parameter for " __FUNCTION__ << endl;
return nullptr;
}
void Empty::NativeFunction( ) { std::cout << "From native function:" __FUNCTION__ << std::endl; }
void NEmpty::NativeBaseFunction( ) { std::cout << "From native function in base:" __FUNCTION__ << std::endl; }
```
See no surprises, no magic code, after macro substitution it's just plain C++.