General rules
- C++26 standard - Use modern C++ features
- 2-space indentation - Configured in
.clang-format - No column limit - Lines can be as long as needed
constexpr/consteval- Use where possible for compile-time evaluationnoexcept- Mark non-throwing functions[[nodiscard]]- Use for functions whose return value matters
Naming conventions
| Element | Style | Example |
|---|---|---|
| Types/Classes | PascalCase | SystemInfo, CacheManager |
| Functions | PascalCase | GetCpuInfo(), GetMemInfo() |
| Variables | camelCase | cpuCount, memoryUsage |
| Constants | SCREAMING_CASE | MAX_BUFFER_SIZE, DEFAULT_TIMEOUT |
| Namespaces | lowercase | draconis::core, draconis::utils |
Examples
Custom type system
Draconis++ uses custom type aliases for improved readability and consistency. Always use these types in new code.Primitive types
| Alias | Standard Type | Description |
|---|---|---|
u8 | std::uint8_t | 8-bit unsigned integer |
u16 | std::uint16_t | 16-bit unsigned integer |
u32 | std::uint32_t | 32-bit unsigned integer |
u64 | std::uint64_t | 64-bit unsigned integer |
i8 | std::int8_t | 8-bit signed integer |
i16 | std::int16_t | 16-bit signed integer |
i32 | std::int32_t | 32-bit signed integer |
i64 | std::int64_t | 64-bit signed integer |
f32 | float | 32-bit floating-point |
f64 | double | 64-bit floating-point |
usize | std::size_t | Unsigned size type |
isize | std::ptrdiff_t | Signed size type |
String types
| Alias | Standard Type | Description |
|---|---|---|
String | std::string | Owning string |
StringView | std::string_view | Non-owning string view |
WString | std::wstring | Wide string (Windows) |
Container types
| Alias | Standard Type | Description |
|---|---|---|
Vec<T> | std::vector<T> | Dynamic array |
Array<T, N> | std::array<T, N> | Fixed-size array |
Span<T> | std::span<T> | Non-owning view of sequence |
Map<K, V> | std::map<K, V> | Ordered map |
UnorderedMap<K, V> | std::unordered_map<K, V> | Hash map |
Pair<T1, T2> | std::pair<T1, T2> | Pair of values |
Smart pointers
| Alias | Standard Type | Description |
|---|---|---|
UniquePointer<T> | std::unique_ptr<T> | Unique ownership |
SharedPointer<T> | std::shared_ptr<T> | Shared ownership |
Result types (error handling)
| Alias | Standard Type | Description |
|---|---|---|
Option<T> | std::optional<T> | Value that may be absent |
Result<T, E> | std::expected<T, E> | Value or error |
Err<E> | std::unexpected<E> | Error wrapper for Result |
None | std::nullopt | Empty Option value |
Type usage guidelines
- Always use custom types in new code
- Import types in
.cppfiles: - Avoid
using namespacein header files - use fully qualified names - Prefer
Result<T>over exceptions for error handling
Function declarations
Use trailing return type syntax with theauto keyword:
Error handling
PreferResult<T> over exceptions for error handling:
Helper functions for Result types
Code formatting
Automatic formatting
All code must be formatted using clang-format before submitting:Key formatting rules
The.clang-format configuration specifies:
- Based on Chromium style with customizations
- 2-space indentation
- No column limit - lines can be as long as needed
- Attach braces - opening brace on same line
- Align consecutive assignments and declarations
- Block indent for arguments
- Namespace indentation - all contents indented
Include order
Headers are automatically organized by clang-format:- System headers (
<vector>,<string>) - Draconis++ headers (
"Drac++/Core/System.hpp") - Draconis++ utility headers (
"Drac++/Utils/Types.hpp") - Local headers (
"LocalFile.hpp")
Best practices
Use constexpr for compile-time values
Mark functions nodiscard appropriately
Use noexcept for non-throwing functions
Prefer auto for type deduction
Running the linter
Check your code with clang-tidy:Next steps
Adding platforms
Learn how to add support for new operating systems
Testing
Write and run tests for your changes