Add Rust and C++ linked list implementations with build/debug configs
Rust version in src/main.rs (Cargo project) and a C++ port in cpp/main.cpp using raw pointers, both with VS Code build tasks and gdb-based debug configs. Vendors vscode-debug-visualizer and visualization as submodules for reference while building a custom node-table graph visualizer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
/cpp/list_example_cpp
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "external/vscode-debug-visualizer"]
|
||||
path = external/vscode-debug-visualizer
|
||||
url = https://github.com/hediet/vscode-debug-visualizer.git
|
||||
[submodule "external/visualization"]
|
||||
path = external/visualization
|
||||
url = https://github.com/hediet/visualization.git
|
||||
57
.vscode/launch.json
vendored
Normal file
57
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug list_example (Rust)",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/target/debug/list_example",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "/usr/bin/rust-gdb",
|
||||
"preLaunchTask": "cargo build",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Debug list_example (C++)",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/cpp/list_example_cpp",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/cpp",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "/usr/bin/gdb",
|
||||
"preLaunchTask": "g++ build cpp/main.cpp",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Don't truncate long arrays (needed for Debug Visualizer JSON)",
|
||||
"text": "-gdb-set print elements 0",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Don't truncate long strings (needed for Debug Visualizer JSON)",
|
||||
"text": "-gdb-set print characters 0",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
35
.vscode/tasks.json
vendored
Normal file
35
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "cargo build",
|
||||
"type": "shell",
|
||||
"command": "cargo",
|
||||
"args": ["build"],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": ["$rustc"]
|
||||
},
|
||||
{
|
||||
"label": "g++ build cpp/main.cpp",
|
||||
"type": "cppbuild",
|
||||
"command": "/usr/bin/g++",
|
||||
"args": [
|
||||
"-std=c++17",
|
||||
"-g",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"${workspaceFolder}/cpp/main.cpp",
|
||||
"-o",
|
||||
"${workspaceFolder}/cpp/list_example_cpp"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/cpp"
|
||||
},
|
||||
"group": "build",
|
||||
"problemMatcher": ["$gcc"]
|
||||
}
|
||||
]
|
||||
}
|
||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "list_example"
|
||||
version = "0.1.0"
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "list_example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
100
cpp/main.cpp
Normal file
100
cpp/main.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
|
||||
// A single node containing data and a raw pointer to the next node
|
||||
template <typename T>
|
||||
struct Node {
|
||||
T data;
|
||||
Node<T>* next;
|
||||
};
|
||||
|
||||
// The main wrapper for the linked list tracking the head node
|
||||
template <typename T>
|
||||
class LinkedList {
|
||||
public:
|
||||
LinkedList() : head_(nullptr) {}
|
||||
|
||||
~LinkedList() {
|
||||
Node<T>* current = head_;
|
||||
while (current) {
|
||||
Node<T>* next = current->next;
|
||||
delete current;
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
// Raw-pointer ownership can't be safely duplicated by a shallow copy
|
||||
LinkedList(const LinkedList&) = delete;
|
||||
LinkedList& operator=(const LinkedList&) = delete;
|
||||
|
||||
// Add a new element to the front of the list
|
||||
void push_front(T data) {
|
||||
head_ = new Node<T>{std::move(data), head_};
|
||||
}
|
||||
|
||||
// Remove and return the front element of the list
|
||||
std::optional<T> pop_front() {
|
||||
if (!head_) {
|
||||
return std::nullopt;
|
||||
}
|
||||
Node<T>* old_head = head_;
|
||||
T data = std::move(old_head->data);
|
||||
head_ = old_head->next;
|
||||
delete old_head;
|
||||
return data;
|
||||
}
|
||||
|
||||
// Read the front element without removing it
|
||||
const T* peek_front() const {
|
||||
return head_ ? &head_->data : nullptr;
|
||||
}
|
||||
|
||||
// Build a JSON string describing the list as a graph, for the VS Code
|
||||
// "Debug Visualizer" extension: watch `list.toDebugGraph()` while paused.
|
||||
// Schema: https://hediet.github.io/visualization/docs/visualization-data-schema.json
|
||||
std::string toDebugGraph() const {
|
||||
std::ostringstream json;
|
||||
json << "{\"kind\":{\"graph\":true},\"nodes\":[";
|
||||
for (Node<T>* n = head_; n; n = n->next) {
|
||||
if (n != head_) json << ",";
|
||||
json << "{\"id\":\"" << n << "\",\"label\":\"" << n->data << "\"}";
|
||||
}
|
||||
json << "],\"edges\":[";
|
||||
for (Node<T>* n = head_; n && n->next; n = n->next) {
|
||||
if (n != head_) json << ",";
|
||||
json << "{\"from\":\"" << n << "\",\"to\":\"" << n->next << "\"}";
|
||||
}
|
||||
json << "]}";
|
||||
return json.str();
|
||||
}
|
||||
|
||||
private:
|
||||
Node<T>* head_;
|
||||
};
|
||||
|
||||
// Force instantiation of every member, including toDebugGraph(), which
|
||||
// nothing in this file calls directly -- without this, gdb has no symbol
|
||||
// to invoke from the debugger's watch expression.
|
||||
template class LinkedList<int>;
|
||||
|
||||
int main() {
|
||||
LinkedList<int> list;
|
||||
|
||||
// Demonstrate pushing items
|
||||
list.push_front(10);
|
||||
list.push_front(20);
|
||||
list.push_front(30);
|
||||
|
||||
// Demonstrate peeking at the top item
|
||||
if (const int* top = list.peek_front()) {
|
||||
std::cout << "Top element: " << *top << "\n"; // Output: 30
|
||||
}
|
||||
|
||||
// Demonstrate popping items
|
||||
while (auto value = list.pop_front()) {
|
||||
std::cout << "Popped: " << *value << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
external/visualization
vendored
Submodule
1
external/visualization
vendored
Submodule
Submodule external/visualization added at 9e6dc9a5ad
1
external/vscode-debug-visualizer
vendored
Submodule
1
external/vscode-debug-visualizer
vendored
Submodule
Submodule external/vscode-debug-visualizer added at 96c26e5388
57
src/main.rs
Normal file
57
src/main.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
// A single node containing data and an optional pointer to the next node
|
||||
struct Node<T> {
|
||||
data: T,
|
||||
next: Option<Box<Node<T>>>,
|
||||
}
|
||||
|
||||
// The main wrapper for the linked list tracking the head node
|
||||
pub struct LinkedList<T> {
|
||||
head: Option<Box<Node<T>>>,
|
||||
}
|
||||
|
||||
impl<T> LinkedList<T> {
|
||||
// Create an empty linked list
|
||||
pub fn new() -> Self {
|
||||
LinkedList { head: None }
|
||||
}
|
||||
|
||||
// Add a new element to the front of the list
|
||||
pub fn push_front(&mut self, data: T) {
|
||||
let new_node = Box::new(Node {
|
||||
data,
|
||||
// .take() temporarily leaves None in self.head and extracts the value
|
||||
next: self.head.take(),
|
||||
});
|
||||
self.head = Some(new_node);
|
||||
}
|
||||
|
||||
// Remove and return the front element of the list
|
||||
pub fn pop_front(&mut self) -> Option<T> {
|
||||
self.head.take().map(|node| {
|
||||
self.head = node.next;
|
||||
node.data
|
||||
})
|
||||
}
|
||||
|
||||
// Read the front element without removing it
|
||||
pub fn peek_front(&self) -> Option<&T> {
|
||||
self.head.as_ref().map(|node| &node.data)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut list = LinkedList::new();
|
||||
|
||||
// Demonstrate pushing items
|
||||
list.push_front(10);
|
||||
list.push_front(20);
|
||||
list.push_front(30);
|
||||
|
||||
// Demonstrate peaking at the top item
|
||||
println!("Top element: {:?}", list.peek_front()); // Output: Some(30)
|
||||
|
||||
// Demonstrate popping items
|
||||
while let Some(value) = list.pop_front() {
|
||||
println!("Popped: {}", value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user