diff --git a/components/ProcessForm.tsx b/components/ProcessForm.tsx
index b7c0116..a735173 100644
--- a/components/ProcessForm.tsx
+++ b/components/ProcessForm.tsx
@@ -16,29 +16,33 @@ import { Input } from "@/components/ui/input";
import { GradientPicker } from "./GradientPicker";
import { useEffect } from "react";
-// Generate a random color (with high saturation)
const generateRandomColor = () => {
const hue = Math.floor(Math.random() * 360);
- const saturation = 60 + Math.floor(Math.random() * 40); // 60-100%
- const lightness = 50 + Math.floor(Math.random() * 20); // 50-70%
+ const saturation = 60 + Math.floor(Math.random() * 40);
+ const lightness = 50 + Math.floor(Math.random() * 20);
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
};
type Process = {
arrival_time: number;
burst_time: number;
+ priority: number;
background: string;
};
const ProcessSchema = z.object({
arrival_time: z.coerce
.number()
- .gt(-1, { message: "Arrival Time cannot be negative." }) // allow 0, disallow negatives
+ .gt(-1, { message: "Arrival Time cannot be negative." })
.lte(100, { message: "Arrival Time cannot be greater than 100." }),
burst_time: z.coerce
.number()
- .gt(0, { message: "Burst Time must be greater than 0." }) // strictly positive
+ .gt(0, { message: "Burst Time must be greater than 0." })
.lte(100, { message: "Burst Time cannot be greater than 100." }),
+ priority: z.coerce
+ .number()
+ .gte(0, { message: "Priority cannot be negative." })
+ .lte(100, { message: "Priority cannot be greater than 100." }),
background: z.string().nonempty({
message: "Please select a background.",
}),
@@ -55,6 +59,7 @@ export function ProcessForm({ addProcess, initialValues }: ProcessFormProps) {
defaultValues: initialValues || {
arrival_time: 0,
burst_time: 1,
+ priority: 0,
background: generateRandomColor(),
},
});
@@ -63,7 +68,6 @@ export function ProcessForm({ addProcess, initialValues }: ProcessFormProps) {
if (initialValues) {
form.reset(initialValues);
} else {
- // Generate new random color for new process
form.setValue("background", generateRandomColor());
}
}, [initialValues, form]);
@@ -73,6 +77,7 @@ export function ProcessForm({ addProcess, initialValues }: ProcessFormProps) {
form.reset({
arrival_time: 0,
burst_time: 1,
+ priority: 0,
background: generateRandomColor(),
});
};
@@ -87,7 +92,7 @@ export function ProcessForm({ addProcess, initialValues }: ProcessFormProps) {
Arrival Time
-
+
@@ -100,7 +105,20 @@ export function ProcessForm({ addProcess, initialValues }: ProcessFormProps) {
Burst Time
-
+
+
+
+
+ )}
+ />
+
(
+
+ Priority (Lower number = Higher priority)
+
+
diff --git a/components/SummaryStatistics.tsx b/components/SummaryStatistics.tsx
index 03f9e43..f2174dd 100644
--- a/components/SummaryStatistics.tsx
+++ b/components/SummaryStatistics.tsx
@@ -5,6 +5,7 @@ type Process = {
process_id: number;
arrival_time: number;
burst_time: number;
+ priority?: number;
background: string;
};
@@ -32,7 +33,9 @@ export default function SummaryStatistics({ totalProcesses, scheduledProcesses }
Throughput
- {Math.round((totalProcesses / totalExecutionTime) * 100) / 100}
+ {totalExecutionTime > 0
+ ? Math.round((totalProcesses / totalExecutionTime) * 100) / 100
+ : 0}
CPU Utilization
diff --git a/components/SummaryTable.tsx b/components/SummaryTable.tsx
index a9cd68b..c4e51fb 100644
--- a/components/SummaryTable.tsx
+++ b/components/SummaryTable.tsx
@@ -19,6 +19,7 @@ type Process = {
process_id: number;
arrival_time: number;
burst_time: number;
+ priority?: number;
background: string;
};
@@ -31,7 +32,6 @@ type SummaryTableProps = {
export function SummaryTable({
originalProcesses,
scheduledProcesses,
- algorithm,
}: SummaryTableProps) {
const [animationKey, setAnimationKey] = useState(0);
@@ -43,72 +43,37 @@ export function SummaryTable({
let totalWaitingTime = 0;
let totalTurnaroundTime = 0;
+ // Build completion time from the actual timeline (includes idle + context switch blocks).
+ const completionByProcessId = new Map
();
+ let timeline = 0;
+ scheduledProcesses.forEach((scheduledProcess) => {
+ timeline += scheduledProcess.burst_time;
+ if (scheduledProcess.process_id > 0) {
+ completionByProcessId.set(scheduledProcess.process_id, timeline);
+ }
+ });
+
// Initialize calculated processes without waiting time calculation
const calculatedProcesses = originalProcesses.map((process) => {
return {
...process,
+ completionTime: 0,
waitingTime: 0,
turnaroundTime: 0,
};
});
- // If the algorithm is FCFS, calculate waiting and turnaround times after sorting by arrival time
-if (algorithm === "FCFS") {
- // Sort processes by arrival time for FCFS order, ignoring idle processes
- const sortedProcesses = [...calculatedProcesses].sort(
- (a, b) => a.arrival_time - b.arrival_time
- );
-
- let cumulativeTime = 0;
-
- // Calculate waiting time and turnaround time for each process
- sortedProcesses.forEach((process) => {
- // Skip idle periods (arrival_time === -1) and adjust cumulative time for gaps
- if (process.arrival_time === -1) {
- return; // Ignore idle periods for waiting and turnaround calculations
- }
-
- // If the next process arrives after the current cumulative time, update for idle time
- if (process.arrival_time > cumulativeTime) {
- cumulativeTime = process.arrival_time; // Adjust to next process arrival, skipping idle time
- }
-
- // Waiting time is the difference between cumulative time and arrival time
- process.waitingTime = Math.max(0, cumulativeTime - process.arrival_time);
-
- // Turnaround time is waiting time + burst time
- process.turnaroundTime = process.waitingTime + process.burst_time;
-
- // Update cumulative time by adding the current process's burst time
- cumulativeTime += process.burst_time;
-
- // Update totals
- totalWaitingTime += process.waitingTime;
- totalTurnaroundTime += process.turnaroundTime;
- });
-} else {
- // For other algorithms, use intervals in scheduledProcesses
+ {
+ // Standard formulas: TAT = CT - AT, WT = TAT - BT.
+ // CT is taken from full timeline so context switching time is naturally included.
calculatedProcesses.forEach((process) => {
- const intervals = scheduledProcesses.filter(
- (scheduledProcess) => scheduledProcess.process_id === process.process_id
- );
-
- let processStartTime = process.arrival_time;
- let waitingTime = 0;
+ const completionTime = completionByProcessId.get(process.process_id) ?? 0;
+ const turnaroundTime = Math.max(completionTime - process.arrival_time, 0);
+ const waitingTime = Math.max(turnaroundTime - process.burst_time, 0);
- intervals.forEach((interval) => {
- if (processStartTime < interval.arrival_time) {
- waitingTime += interval.arrival_time - processStartTime;
- }
- processStartTime = interval.arrival_time + interval.burst_time;
- });
-
- const turnaroundTime =
- waitingTime +
- intervals.reduce((sum, interval) => sum + interval.burst_time, 0);
-
- process.waitingTime = waitingTime;
+ process.completionTime = completionTime;
process.turnaroundTime = turnaroundTime;
+ process.waitingTime = waitingTime;
// Update cumulative totals
totalWaitingTime += waitingTime;
@@ -120,21 +85,17 @@ if (algorithm === "FCFS") {
turnaroundTime = totalTurnaroundTime;
// Calculate CPU utilization
- const totalBurstTime = scheduledProcesses.reduce(
- (sum, process) => process.arrival_time !== -1?sum + process.burst_time:sum+0 ,
+ const totalBurstTime = originalProcesses.reduce(
+ (sum, process) => sum + process.burst_time,
0
);
- const startTime = Math.min(
- ...scheduledProcesses.map((process) => process.arrival_time)
+ totalExecutionTime = scheduledProcesses.reduce(
+ (sum, process) => sum + process.burst_time,
+ 0
);
- const endTime =
- startTime +
- scheduledProcesses.reduce((sum, process) => sum + process.burst_time, 0);
-
- totalExecutionTime = endTime - startTime;
- cpuUtilization = (totalBurstTime / totalExecutionTime) * 100;
+ cpuUtilization = totalExecutionTime > 0 ? (totalBurstTime / totalExecutionTime) * 100 : 0;
const popOutVariants = {
hidden: { scale: 0.8, opacity: 0 },
@@ -172,11 +133,14 @@ if (algorithm === "FCFS") {
Burst Time
- Waiting Time
+ Completion Time
Turnaround Time
+
+ Waiting Time
+
@@ -200,17 +164,20 @@ if (algorithm === "FCFS") {
{process.burst_time}
- {process.waitingTime}
+ {process.completionTime}
{process.turnaroundTime}
+
+ {process.waitingTime}
+
))}
-
+
Total
{totalWaitingTime}
diff --git a/components/footer.tsx b/components/footer.tsx
index fd1d21c..6e1ffdf 100644
--- a/components/footer.tsx
+++ b/components/footer.tsx
@@ -1,29 +1,63 @@
-import Link from "next/link";
-import { GitHubLogoIcon } from "@radix-ui/react-icons";
+"use client";
+
+import { useEffect, useState } from "react";
+
+type NativeStatusResponse = {
+ nativeLoaded: boolean;
+ addonExists: boolean;
+ addonPath: string;
+};
export default function Footer() {
- return (
-
- );
+ const [status, setStatus] = useState(null);
+
+ useEffect(() => {
+ let mounted = true;
+
+ const loadStatus = async () => {
+ try {
+ const response = await fetch("/api/native-status", { cache: "no-store" });
+ if (!response.ok) {
+ return;
+ }
+ const payload = (await response.json()) as NativeStatusResponse;
+ if (mounted) {
+ setStatus(payload);
+ }
+ } catch {
+ // Keep footer resilient if the endpoint is unavailable.
+ }
+ };
+
+ loadStatus();
+ return () => {
+ mounted = false;
+ };
+ }, []);
+
+ const nativeOn = Boolean(status?.nativeLoaded);
+
+ return (
+
+ );
}
diff --git a/cpp/include/Algorithms.h b/cpp/include/Algorithms.h
new file mode 100644
index 0000000..a50bc33
--- /dev/null
+++ b/cpp/include/Algorithms.h
@@ -0,0 +1,25 @@
+#ifndef ALGORITHMS_H
+#define ALGORITHMS_H
+
+#include "Process.h"
+#include
+
+// First Come First Serve
+std::vector firstComeFirstServe(const std::vector &processes);
+
+// Round Robin
+std::vector roundRobin(const std::vector &processes, int quantum);
+
+// Shortest Job First
+std::vector shortestJobFirst(const std::vector &processes);
+
+// Shortest Remaining Time First
+std::vector shortestRemainingTimeFirst(const std::vector &processes);
+
+// Priority Non-Preemptive
+std::vector priorityNonPreemptive(const std::vector &processes);
+
+// Priority Preemptive
+std::vector priorityPreemptive(const std::vector &processes);
+
+#endif // ALGORITHMS_H
diff --git a/cpp/include/Process.h b/cpp/include/Process.h
new file mode 100644
index 0000000..e36800c
--- /dev/null
+++ b/cpp/include/Process.h
@@ -0,0 +1,23 @@
+#ifndef PROCESS_H
+#define PROCESS_H
+
+#include
+
+struct Process
+{
+ int process_id;
+ int arrival_time;
+ int burst_time;
+ int priority;
+ std::string background;
+
+ Process() : process_id(0), arrival_time(0), burst_time(0), priority(0), background("") {}
+
+ Process(int id, int arrival, int burst, const std::string &bg)
+ : process_id(id), arrival_time(arrival), burst_time(burst), priority(0), background(bg) {}
+
+ Process(int id, int arrival, int burst, int prio, const std::string &bg)
+ : process_id(id), arrival_time(arrival), burst_time(burst), priority(prio), background(bg) {}
+};
+
+#endif // PROCESS_H
diff --git a/cpp/src/FirstComeFirstServe.cpp b/cpp/src/FirstComeFirstServe.cpp
new file mode 100644
index 0000000..8514347
--- /dev/null
+++ b/cpp/src/FirstComeFirstServe.cpp
@@ -0,0 +1,30 @@
+#include "Algorithms.h"
+#include
+
+std::vector firstComeFirstServe(const std::vector& processes) {
+ // Sort processes by arrival time
+ std::vector sortedProcesses = processes;
+ std::sort(sortedProcesses.begin(), sortedProcesses.end(),
+ [](const Process& a, const Process& b) {
+ return a.arrival_time < b.arrival_time;
+ });
+
+ std::vector result;
+ int currentTime = 0;
+
+ for (size_t i = 0; i < sortedProcesses.size(); i++) {
+ const Process& currentProcess = sortedProcesses[i];
+
+ if (currentProcess.arrival_time > currentTime) {
+ int gapDuration = currentProcess.arrival_time - currentTime;
+ Process gap(-1, -1, gapDuration, "transparent");
+ result.push_back(gap);
+ currentTime = currentProcess.arrival_time;
+ }
+
+ result.push_back(currentProcess);
+ currentTime += currentProcess.burst_time;
+ }
+
+ return result;
+}
diff --git a/cpp/src/PriorityNonPreemptive.cpp b/cpp/src/PriorityNonPreemptive.cpp
new file mode 100644
index 0000000..4f9f361
--- /dev/null
+++ b/cpp/src/PriorityNonPreemptive.cpp
@@ -0,0 +1,63 @@
+#include "Algorithms.h"
+#include
+#include
+
+std::vector priorityNonPreemptive(const std::vector &processes)
+{
+ // Sort processes by arrival time first
+ std::vector sortedProcesses = processes;
+ std::sort(sortedProcesses.begin(), sortedProcesses.end(),
+ [](const Process &a, const Process &b)
+ {
+ return a.arrival_time < b.arrival_time;
+ });
+
+ std::vector result;
+ std::vector completed(sortedProcesses.size(), false);
+ int currentTime = 0;
+
+ for (size_t i = 0; i < sortedProcesses.size(); i++)
+ {
+ int nextProcess = -1;
+ int highestPriority = INT_MAX;
+
+ // Find the highest priority process that has arrived and not completed
+ for (size_t j = 0; j < sortedProcesses.size(); j++)
+ {
+ if (!completed[j] && sortedProcesses[j].arrival_time <= currentTime)
+ {
+ if (sortedProcesses[j].priority < highestPriority)
+ {
+ highestPriority = sortedProcesses[j].priority;
+ nextProcess = j;
+ }
+ }
+ }
+
+ // If no process has arrived, jump to the next arrival time
+ if (nextProcess == -1)
+ {
+ for (size_t j = 0; j < sortedProcesses.size(); j++)
+ {
+ if (!completed[j] && sortedProcesses[j].arrival_time > currentTime)
+ {
+ int gapDuration = sortedProcesses[j].arrival_time - currentTime;
+ Process gap(-1, -1, gapDuration, 0, "transparent");
+ result.push_back(gap);
+ currentTime = sortedProcesses[j].arrival_time;
+ break;
+ }
+ }
+ i = -1; // Restart the loop to find the next process
+ continue;
+ }
+
+ // Execute the selected process
+ const Process ¤tProcess = sortedProcesses[nextProcess];
+ result.push_back(currentProcess);
+ currentTime += currentProcess.burst_time;
+ completed[nextProcess] = true;
+ }
+
+ return result;
+}
diff --git a/cpp/src/PriorityPreemptive.cpp b/cpp/src/PriorityPreemptive.cpp
new file mode 100644
index 0000000..7b3cdda
--- /dev/null
+++ b/cpp/src/PriorityPreemptive.cpp
@@ -0,0 +1,83 @@
+#include "Algorithms.h"
+#include
+#include
+#include
+
+std::vector priorityPreemptive(const std::vector &processes)
+{
+ std::vector result;
+ std::vector sortedProcesses = processes;
+
+ // Sort by arrival time
+ std::sort(sortedProcesses.begin(), sortedProcesses.end(),
+ [](const Process &a, const Process &b)
+ {
+ return a.arrival_time < b.arrival_time;
+ });
+
+ // Track remaining time for each process
+ std::vector remainingTime(sortedProcesses.size());
+ for (size_t i = 0; i < sortedProcesses.size(); i++)
+ {
+ remainingTime[i] = sortedProcesses[i].burst_time;
+ }
+
+ int currentTime = 0;
+ int completedCount = 0;
+ size_t nextArrivalIdx = 0;
+
+ while (completedCount < sortedProcesses.size())
+ {
+ // Find the next available process with highest priority
+ int nextProcess = -1;
+ int highestPriority = INT_MAX;
+
+ // Add newly arrived processes
+ while (nextArrivalIdx < sortedProcesses.size() &&
+ sortedProcesses[nextArrivalIdx].arrival_time <= currentTime)
+ {
+ nextArrivalIdx++;
+ }
+
+ // Find highest priority process that has arrived
+ for (size_t i = 0; i < sortedProcesses.size(); i++)
+ {
+ if (remainingTime[i] > 0 && sortedProcesses[i].arrival_time <= currentTime)
+ {
+ if (sortedProcesses[i].priority < highestPriority)
+ {
+ highestPriority = sortedProcesses[i].priority;
+ nextProcess = i;
+ }
+ }
+ }
+
+ // If no process available, jump to next arrival
+ if (nextProcess == -1)
+ {
+ if (nextArrivalIdx < sortedProcesses.size())
+ {
+ int gapDuration = sortedProcesses[nextArrivalIdx].arrival_time - currentTime;
+ Process gap(-1, -1, gapDuration, 0, "transparent");
+ result.push_back(gap);
+ currentTime = sortedProcesses[nextArrivalIdx].arrival_time;
+ }
+ continue;
+ }
+
+ // Execute for 1 time unit
+ const Process ¤tProcess = sortedProcesses[nextProcess];
+ Process executing(currentProcess.process_id, currentTime, 1, currentProcess.priority, currentProcess.background);
+ result.push_back(executing);
+
+ remainingTime[nextProcess]--;
+ currentTime++;
+
+ if (remainingTime[nextProcess] == 0)
+ {
+ completedCount++;
+ }
+ }
+
+ return result;
+}
diff --git a/cpp/src/RoundRobin.cpp b/cpp/src/RoundRobin.cpp
new file mode 100644
index 0000000..7349958
--- /dev/null
+++ b/cpp/src/RoundRobin.cpp
@@ -0,0 +1,90 @@
+#include "Algorithms.h"
+#include
+#include
+
+struct QueueItem {
+ Process process;
+ int remaining_time;
+};
+
+std::vector roundRobin(const std::vector& processes, int quantum) {
+ // Sort processes by arrival time
+ std::vector sortedProcesses = processes;
+ std::sort(sortedProcesses.begin(), sortedProcesses.end(),
+ [](const Process& a, const Process& b) {
+ return a.arrival_time < b.arrival_time;
+ });
+
+ std::vector result;
+ std::queue queue;
+ int currentTime = 0;
+ size_t index = 0;
+
+ while (!queue.empty() || index < sortedProcesses.size()) {
+ // Enqueue newly arrived processes
+ while (index < sortedProcesses.size() &&
+ sortedProcesses[index].arrival_time <= currentTime) {
+ QueueItem item;
+ item.process = sortedProcesses[index];
+ item.remaining_time = sortedProcesses[index].burst_time;
+ queue.push(item);
+ index++;
+ }
+
+ if (queue.empty()) {
+ // Idle time until the next process arrives
+ const Process& nextProcess = sortedProcesses[index];
+ int gapDuration = nextProcess.arrival_time - currentTime;
+ Process gap(-1, -1, gapDuration, "transparent");
+ result.push_back(gap);
+ currentTime += gapDuration;
+ } else {
+ // Dequeue a process and execute it for the quantum or until it finishes
+ QueueItem item = queue.front();
+ queue.pop();
+
+ int executionTime = (item.remaining_time < quantum) ? item.remaining_time : quantum;
+
+ // Add the process slice to the result
+ Process executed = item.process;
+ executed.arrival_time = currentTime;
+ executed.burst_time = executionTime;
+ result.push_back(executed);
+
+ currentTime += executionTime;
+
+ // Re-check for newly arrived processes after execution
+ while (index < sortedProcesses.size() &&
+ sortedProcesses[index].arrival_time <= currentTime) {
+ QueueItem newItem;
+ newItem.process = sortedProcesses[index];
+ newItem.remaining_time = sortedProcesses[index].burst_time;
+ queue.push(newItem);
+ index++;
+ }
+
+ // If the process has remaining time, requeue it
+ if (item.remaining_time > quantum) {
+ QueueItem requeue;
+ requeue.process = item.process;
+ requeue.remaining_time = item.remaining_time - quantum;
+ queue.push(requeue);
+ }
+ }
+ }
+
+ // Merge consecutive executions of the same process
+ std::vector mergedResult;
+ for (size_t i = 0; i < result.size(); i++) {
+ const Process& currentProcess = result[i];
+
+ if (!mergedResult.empty() &&
+ mergedResult.back().process_id == currentProcess.process_id) {
+ mergedResult.back().burst_time += currentProcess.burst_time;
+ } else {
+ mergedResult.push_back(currentProcess);
+ }
+ }
+
+ return mergedResult;
+}
diff --git a/cpp/src/ShortestJobFirst.cpp b/cpp/src/ShortestJobFirst.cpp
new file mode 100644
index 0000000..a16e521
--- /dev/null
+++ b/cpp/src/ShortestJobFirst.cpp
@@ -0,0 +1,65 @@
+#include "Algorithms.h"
+#include
+
+std::vector shortestJobFirst(const std::vector& processes) {
+ // Clone and sort the processes by arrival time
+ std::vector sortedProcesses = processes;
+ std::sort(sortedProcesses.begin(), sortedProcesses.end(),
+ [](const Process& a, const Process& b) {
+ return a.arrival_time < b.arrival_time;
+ });
+
+ std::vector result;
+ std::vector availableProcesses;
+ int currentTime = 0;
+ size_t index = 0;
+
+ while (index < sortedProcesses.size() || !availableProcesses.empty()) {
+ // Move processes that have arrived by currentTime into available processes
+ while (index < sortedProcesses.size() &&
+ sortedProcesses[index].arrival_time <= currentTime) {
+ availableProcesses.push_back(sortedProcesses[index]);
+ index++;
+ }
+
+ // If there are available processes, pick the one with the shortest burst time
+ if (!availableProcesses.empty()) {
+ // Sort by burst time to find the shortest job
+ std::sort(availableProcesses.begin(), availableProcesses.end(),
+ [](const Process& a, const Process& b) {
+ return a.burst_time < b.burst_time;
+ });
+
+ Process nextProcess = availableProcesses[0];
+ availableProcesses.erase(availableProcesses.begin());
+
+ // Add the selected process to the result
+ nextProcess.arrival_time = currentTime;
+ result.push_back(nextProcess);
+
+ currentTime += nextProcess.burst_time;
+ } else {
+ // If no processes are available, create an idle gap
+ const Process& nextProcess = sortedProcesses[index];
+ int gapDuration = nextProcess.arrival_time - currentTime;
+ Process gap(-1, -1, gapDuration, "transparent");
+ result.push_back(gap);
+ currentTime += gapDuration;
+ }
+ }
+
+ // Merge consecutive executions of the same process
+ std::vector mergedResult;
+ for (size_t i = 0; i < result.size(); i++) {
+ const Process& currentProcess = result[i];
+
+ if (!mergedResult.empty() &&
+ mergedResult.back().process_id == currentProcess.process_id) {
+ mergedResult.back().burst_time += currentProcess.burst_time;
+ } else {
+ mergedResult.push_back(currentProcess);
+ }
+ }
+
+ return mergedResult;
+}
diff --git a/cpp/src/ShortestRemainingTimeFirst.cpp b/cpp/src/ShortestRemainingTimeFirst.cpp
new file mode 100644
index 0000000..a72248e
--- /dev/null
+++ b/cpp/src/ShortestRemainingTimeFirst.cpp
@@ -0,0 +1,95 @@
+#include "Algorithms.h"
+#include
+
+struct QueueItem {
+ Process process;
+ int remaining_time;
+};
+
+std::vector shortestRemainingTimeFirst(const std::vector& processes) {
+ // Sort processes by arrival time
+ std::vector sortedProcesses = processes;
+ std::sort(sortedProcesses.begin(), sortedProcesses.end(),
+ [](const Process& a, const Process& b) {
+ return a.arrival_time < b.arrival_time;
+ });
+
+ std::vector result;
+ std::vector queue;
+ int currentTime = 0;
+ size_t index = 0;
+
+ while (!queue.empty() || index < sortedProcesses.size()) {
+ // Enqueue newly arrived processes
+ while (index < sortedProcesses.size() &&
+ sortedProcesses[index].arrival_time <= currentTime) {
+ QueueItem item;
+ item.process = sortedProcesses[index];
+ item.remaining_time = sortedProcesses[index].burst_time;
+ queue.push_back(item);
+ index++;
+ }
+
+ // Sort the queue by remaining time (shortest remaining time first)
+ std::sort(queue.begin(), queue.end(),
+ [](const QueueItem& a, const QueueItem& b) {
+ return a.remaining_time < b.remaining_time;
+ });
+
+ if (queue.empty()) {
+ // Idle time until the next process arrives
+ const Process& nextProcess = sortedProcesses[index];
+ int gapDuration = nextProcess.arrival_time - currentTime;
+ Process gap(-1, -1, gapDuration, "transparent");
+ result.push_back(gap);
+ currentTime += gapDuration;
+ } else {
+ // Pick the process with the shortest remaining time
+ QueueItem item = queue[0];
+ queue.erase(queue.begin());
+
+ int executionTime = 1; // SRTF executes in 1 time unit intervals for preemption
+
+ // Add the process slice to the result
+ Process executed = item.process;
+ executed.arrival_time = currentTime;
+ executed.burst_time = executionTime;
+ result.push_back(executed);
+
+ currentTime += executionTime;
+
+ // Re-check for newly arrived processes after execution
+ while (index < sortedProcesses.size() &&
+ sortedProcesses[index].arrival_time <= currentTime) {
+ QueueItem newItem;
+ newItem.process = sortedProcesses[index];
+ newItem.remaining_time = sortedProcesses[index].burst_time;
+ queue.push_back(newItem);
+ index++;
+ }
+
+ // If the process has remaining time, requeue it
+ if (item.remaining_time > executionTime) {
+ QueueItem requeue;
+ requeue.process = item.process;
+ requeue.remaining_time = item.remaining_time - executionTime;
+ queue.push_back(requeue);
+ }
+ }
+ }
+
+ // Merge consecutive processes with the same process_id
+ std::vector mergedResult;
+ for (size_t i = 0; i < result.size(); i++) {
+ const Process& currentProcess = result[i];
+
+ if (!mergedResult.empty() &&
+ mergedResult.back().process_id == currentProcess.process_id) {
+ mergedResult.back().burst_time += currentProcess.burst_time;
+ } else {
+ mergedResult.push_back(currentProcess);
+ }
+ }
+
+ return mergedResult;
+}
diff --git a/cpp/src/binding.cc b/cpp/src/binding.cc
new file mode 100644
index 0000000..dde2424
--- /dev/null
+++ b/cpp/src/binding.cc
@@ -0,0 +1,242 @@
+#include
+#include
+#include "Algorithms.h"
+#include
+
+namespace scheduling
+{
+
+ using v8::Array;
+ using v8::Exception;
+ using v8::FunctionCallbackInfo;
+ using v8::Isolate;
+ using v8::Local;
+ using v8::NewStringType;
+ using v8::Number;
+ using v8::Object;
+ using v8::String;
+ using v8::Value;
+
+ // Helper function to convert v8 Array of objects to std::vector
+ std::vector ArrayToProcessVector(Isolate *isolate, Local array)
+ {
+ std::vector processes;
+
+ for (uint32_t i = 0; i < array->Length(); i++)
+ {
+ Local element = array->Get(isolate->GetCurrentContext(), i).ToLocalChecked();
+
+ if (!element->IsObject())
+ {
+ isolate->ThrowException(Exception::TypeError(
+ String::NewFromUtf8(isolate, "Array elements must be objects").ToLocalChecked()));
+ return processes;
+ }
+
+ Local