[feature] First Update
This commit is contained in:
commit
2d81ced29a
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
|
@ -0,0 +1,13 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>操作系统实验</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "operating-system",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"echarts": "^5.5.1",
|
||||
"pinia": "^2.2.6",
|
||||
"tdesign-vue-next": "^1.10.4",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||
"less": "^4.2.1",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^6.0.1",
|
||||
"vue-tsc": "^2.1.10"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,30 @@
|
|||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<RouterLink to="/expr1" class="link-button">
|
||||
<t-button>
|
||||
<p>实验一</p>
|
||||
</t-button>
|
||||
</RouterLink>
|
||||
<RouterLink to="/expr2" class="link-button">
|
||||
<t-button>
|
||||
实验二
|
||||
</t-button>
|
||||
</RouterLink>
|
||||
</header>
|
||||
<main>
|
||||
<RouterView/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.link-button {
|
||||
margin-right: 5px;
|
||||
}
|
||||
header{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
|
@ -0,0 +1,29 @@
|
|||
<script setup lang="tsx">
|
||||
|
||||
import RAM from "@/components/expr1/RAM.vue";
|
||||
import OperationTable from "@/components/expr1/OperationTable.vue";
|
||||
import {provide} from "vue";
|
||||
import {Ram} from "@/logical/expr1/ram.ts";
|
||||
import ControlPanel from "@/components/expr1/ControlPanel.vue";
|
||||
|
||||
let ram = new Ram();
|
||||
provide("ram", ram);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<control-panel/>
|
||||
<RAM/>
|
||||
<div id="operation-table">
|
||||
<operation-table/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
#operations {
|
||||
width: 690px;
|
||||
}
|
||||
|
||||
#operation-table {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<script setup lang="ts">
|
||||
import useExpr1Store from "@/store/expr1/expr1Store.ts";
|
||||
import {storeToRefs} from "pinia";
|
||||
import {Ram} from "@/logical/expr1/ram.ts";
|
||||
import {inject} from "vue";
|
||||
|
||||
let {tableChanged, failInfo, memSize} = storeToRefs(useExpr1Store());
|
||||
let ram: Ram = inject("ram")!;
|
||||
function onChange(checkedValues: string) {
|
||||
ram.CurrentSelector = parseInt(checkedValues);
|
||||
tableChanged.value = true;
|
||||
}
|
||||
function onMemoryChange() {
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<t-space direction="horizontal" :size="22">
|
||||
<t-typography-text>内存大小</t-typography-text>
|
||||
<t-input-number @change="onMemoryChange" v-model:value="memSize" theme="column"></t-input-number>
|
||||
<t-radio-group default-value="0" @change="onChange">
|
||||
<t-radio value="0">FirstFit</t-radio>
|
||||
<t-radio value="1">BestFit</t-radio>
|
||||
<t-radio value="2">WorstFit</t-radio>
|
||||
</t-radio-group>
|
||||
<t-typography-text theme="error">{{ failInfo }}</t-typography-text>
|
||||
</t-space>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
|
@ -0,0 +1,239 @@
|
|||
<script setup lang="tsx">
|
||||
|
||||
import useExpr1Store from "@/store/expr1/expr1Store.ts";
|
||||
import {storeToRefs} from "pinia";
|
||||
import {Input, RowClassNameParams, Select} from "tdesign-vue-next";
|
||||
import {Operation} from "@/store/expr1/defaultOperation.ts";
|
||||
import {computed, inject} from "vue";
|
||||
import {Ram} from "@/logical/expr1/ram.ts";
|
||||
|
||||
const typeListMap = {
|
||||
'request': {
|
||||
label: '申请',
|
||||
theme: 'success',
|
||||
},
|
||||
'release': {
|
||||
label: '释放',
|
||||
theme: 'primary',
|
||||
},
|
||||
}
|
||||
let expr1Store = useExpr1Store();
|
||||
let ram: Ram = inject("ram")!;
|
||||
let beforeKey = -1;
|
||||
const {operations, tableChanged, currentState} = storeToRefs(expr1Store);
|
||||
const data = computed(() => {
|
||||
return operations.value.map((operation: Operation, index: number) => {
|
||||
return {
|
||||
key: String(index + 1),
|
||||
id: operation.id,
|
||||
type: operation.type,
|
||||
memorySize: operation.type === "release" ? ram.GetReleaseHistory(operation.id) : operation.memorySize,
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
function OnTableBlur(row: number, col: number, value: number | string) {
|
||||
if (col === 1 || col === 3) {
|
||||
if (typeof value === 'string')
|
||||
value = parseInt(value as string);
|
||||
if (value == undefined || (value as number) < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (col) {
|
||||
case 1:
|
||||
operations.value[row].id = value as number;
|
||||
break;
|
||||
case 2:
|
||||
operations.value[row].type = value as "request" | "release";
|
||||
break;
|
||||
case 3:
|
||||
if (operations.value[row].type === 'request')
|
||||
operations.value[row].memorySize = value as number;
|
||||
break;
|
||||
}
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '任务编号',
|
||||
colKey: 'key',
|
||||
className: 'id-col',
|
||||
},
|
||||
{
|
||||
title: '进程编号',
|
||||
colKey: 'id',
|
||||
className: 'process-id-col',
|
||||
edit: {
|
||||
component: Input,
|
||||
props: {
|
||||
clearable: true,
|
||||
autofocus: true,
|
||||
autoWidth: true,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
{
|
||||
pattern: /^[+-]?(\d+(\.\d*)?|\.\d+)$/,
|
||||
message: '请输入数字',
|
||||
},
|
||||
{
|
||||
pattern: /^\d+(\.\d+)?$/,
|
||||
message: '请输入正数',
|
||||
}
|
||||
],
|
||||
on: ({rowIndex, colIndex}: {
|
||||
rowIndex: number,
|
||||
colIndex: number,
|
||||
}) => ({
|
||||
onBlur: (value: number) => OnTableBlur(rowIndex, colIndex, value)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作类型', colKey: 'type', cell: (_: any, {row}: RowClassNameParams<Operation>) => {
|
||||
return (
|
||||
<t-tag shape="round" theme={typeListMap[row.type].theme} variant="light-outline">
|
||||
{typeListMap[row.type].label}
|
||||
</t-tag>
|
||||
);
|
||||
},
|
||||
edit: {
|
||||
component: Select,
|
||||
props: {
|
||||
clearable: true,
|
||||
autofocus: true,
|
||||
autoWidth: true,
|
||||
options: [
|
||||
{label: '申请', value: 'request'},
|
||||
{label: '释放', value: 'release'},
|
||||
]
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
on: ({rowIndex, colIndex}: {
|
||||
rowIndex: number,
|
||||
colIndex: number,
|
||||
}) => ({
|
||||
onChange: ({value}: {
|
||||
value: string
|
||||
}) => OnTableBlur(rowIndex, colIndex, value)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '涉及内存大小',
|
||||
colKey: 'memorySize',
|
||||
className: 'memory-size',
|
||||
edit: {
|
||||
component: Input,
|
||||
props: {
|
||||
clearable: true,
|
||||
autofocus: true,
|
||||
autoWidth: true,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
{
|
||||
pattern: /^[+-]?(\d+(\.\d*)?|\.\d+)$/,
|
||||
message: '请输入数字',
|
||||
},
|
||||
{
|
||||
pattern: /^\d+(\.\d+)?$/,
|
||||
message: '请输入正数',
|
||||
}
|
||||
],
|
||||
on: ({rowIndex, colIndex}: {
|
||||
rowIndex: number,
|
||||
colIndex: number,
|
||||
}) => ({
|
||||
onBlur: (value: number) => OnTableBlur(rowIndex, colIndex, value)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
colKey: 'operation',
|
||||
title: '操作',
|
||||
width: 140
|
||||
}
|
||||
];
|
||||
|
||||
function GetRowName(params: RowClassNameParams<Operation>): string {
|
||||
const row = params.row;
|
||||
return row.type === 'request' ? 'request-row' : 'release-row';
|
||||
}
|
||||
|
||||
function MouseEnter({row}: { row: { key: string } }) {
|
||||
beforeKey = currentState.value;
|
||||
currentState.value = parseInt(row.key);
|
||||
//console.log(detailMemoryIndex.value)
|
||||
}
|
||||
|
||||
function MouseLeave() {
|
||||
currentState.value = beforeKey;
|
||||
}
|
||||
|
||||
function MouseClick({row}: { row: { key: string } }) {
|
||||
currentState.value = -1;
|
||||
beforeKey = parseInt(row.key);
|
||||
currentState.value = beforeKey;
|
||||
}
|
||||
|
||||
function InsertBefore(row: number) {
|
||||
operations.value.splice(row - 1, 0, {
|
||||
id: 0,
|
||||
type: 'request',
|
||||
memorySize: 0,
|
||||
});
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
function InsertEnd() {
|
||||
operations.value.push({
|
||||
id: 0,
|
||||
type: 'request',
|
||||
memorySize: 0,
|
||||
});
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
function Delete(row: number) {
|
||||
operations.value.splice(row - 1, 1);
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="operations">
|
||||
<t-table row-key="key" :columns="columns" :data="data" :hover="true" :row-class-name="GetRowName" :stripe="true"
|
||||
:resizable=true @row-mouseenter="MouseEnter" @row-mouseleave="MouseLeave" @row-mousedown="MouseClick"
|
||||
:column-controller="{displayType: 'auto-width',hideTriggerButton: true}">
|
||||
<template #operation="{ row }">
|
||||
<t-link style="display: inline" theme="primary" hover="color" @click="InsertBefore(parseInt(row.key))">
|
||||
在之前插入
|
||||
</t-link>
|
||||
<t-link theme="primary" hover="color" @click.stop="Delete(parseInt(row.key))">
|
||||
删除
|
||||
</t-link>
|
||||
</template>
|
||||
</t-table>
|
||||
<t-button @click="InsertEnd">新增一条操作</t-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
|
@ -0,0 +1,115 @@
|
|||
<script setup lang="ts">
|
||||
import {Block, Ram} from "@/logical/expr1/ram.ts";
|
||||
import {computed, inject} from "vue";
|
||||
import useExpr1Store from "@/store/expr1/expr1Store.ts";
|
||||
import {storeToRefs} from "pinia";
|
||||
|
||||
interface RamBlock extends Block {
|
||||
Index: number;
|
||||
Flex: number;
|
||||
StartFrom: number;
|
||||
}
|
||||
|
||||
let ram: Ram = inject("ram")!;
|
||||
const {detailMemoryIndex, currentState} = storeToRefs(useExpr1Store());
|
||||
let startFrom = 0;
|
||||
let blocks = computed(() => {
|
||||
let memory = ram.GetMemory();
|
||||
let blocks: RamBlock[] = [];
|
||||
for (let i = 0; i < memory.length; i++) {
|
||||
blocks.push({
|
||||
...memory[i],
|
||||
Index: i,
|
||||
Flex: memory[i].MemorySize / ram._memSize.value,
|
||||
StartFrom: startFrom
|
||||
});
|
||||
startFrom += memory[i].MemorySize;
|
||||
}
|
||||
return blocks;
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>CurrentState: {{ currentState }}</p>
|
||||
<div class="memory">
|
||||
<div v-for="block in blocks" :key="block.Index" :style="{flex: block.Flex}" class="block"
|
||||
:class="block.Type" @mouseenter="detailMemoryIndex = block.Index"
|
||||
@mouseleave="detailMemoryIndex = -1">
|
||||
<p v-if="block.Type === 'Process'">Process {{ block.ProcessID }}<br>{{ block.MemorySize }} </p>
|
||||
<p v-else></p>
|
||||
<div v-if="block.Index === detailMemoryIndex" class="tip"
|
||||
@mouseover="detailMemoryIndex = block.Index">
|
||||
<span v-if="block.Type==='Process'">Process {{
|
||||
block.ProcessID
|
||||
}}<br>Start From: {{ block.StartFrom }}<br>Space: {{ block.MemorySize }}</span>
|
||||
<span v-else>Free Space<br>Start From: {{ block.StartFrom }}<br>Space: {{ block.MemorySize }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.fade-move, .fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 2s;
|
||||
}
|
||||
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fade-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
.memory {
|
||||
margin-top: 70px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 200px;
|
||||
width: 80vw;
|
||||
background-color: #181818;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.Process {
|
||||
border: #cccaff 1px solid;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Process p {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
}
|
||||
|
||||
.block {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Space {
|
||||
background: repeating-linear-gradient(45deg, /* Angle of the stripes */ #cccaff, /* Color 1 */ #cccaff 10px, /* Color 1 stop */ #000000 10px, /* Color 2 start */ #000000 20px /* Color 2 stop */);
|
||||
height: 100%;
|
||||
border: #cccaff 1px solid;
|
||||
}
|
||||
|
||||
.tip {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
z-index: 20;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
|
||||
import DISK from "@/components/expr2/DISK.vue";
|
||||
import OperationTable from "@/components/expr2/OperationTable.vue";
|
||||
import OperationGraph from "@/components/expr2/OperationGraph.vue";
|
||||
import ControlPanel from "@/components/expr2/ControlPanel.vue";
|
||||
import {Disk} from "@/logical/expr2/disk.ts";
|
||||
import {provide} from "vue";
|
||||
provide("disk",new Disk());
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ControlPanel/>
|
||||
<div style="display: flex">
|
||||
<DISK/>
|
||||
<OperationGraph/>
|
||||
</div>
|
||||
<OperationTable/>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<script setup lang="ts">
|
||||
import {storeToRefs} from "pinia";
|
||||
import useExpr2Store from "@/store/expr2/expr2Store.ts";
|
||||
|
||||
let {tableChanged, failInfo, trackCount, algorithm, startTrack} = storeToRefs(useExpr2Store());
|
||||
function onChange(checkedValues: string) {
|
||||
algorithm.value = parseInt(checkedValues);
|
||||
tableChanged.value = true;
|
||||
}
|
||||
function onTrackChange() {
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<t-space direction="horizontal" :size="22">
|
||||
<t-typography-text>磁道数量</t-typography-text>
|
||||
<t-input-number @change="onTrackChange" v-model:value="trackCount" theme="column"></t-input-number>
|
||||
<t-typography-text>起始磁道</t-typography-text>
|
||||
<t-input-number @change="onTrackChange" v-model:value="startTrack" theme="column"></t-input-number>
|
||||
<t-radio-group default-value="0" @change="onChange">
|
||||
<t-radio value="0">FCFS</t-radio>
|
||||
<t-radio value="1">SSTF</t-radio>
|
||||
<t-radio value="2">SCAN_FirstDown</t-radio>
|
||||
<t-radio value="3">SCAN_FirstUp</t-radio>
|
||||
</t-radio-group>
|
||||
<t-typography-text theme="error">{{ failInfo }}</t-typography-text>
|
||||
</t-space>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
|
@ -0,0 +1,131 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
computed, ref, watch
|
||||
} from "vue";
|
||||
import {storeToRefs} from "pinia";
|
||||
import useExpr2Store from "@/store/expr2/expr2Store.ts";
|
||||
//18 <-> -12
|
||||
const duration = 1, animationCount = 40;
|
||||
const {currentTrack, trackCount, trackFromIndex, trackToIndex, operations, startTrack,selectTrackFromIndex,selectTrackToIndex} = storeToRefs(useExpr2Store());
|
||||
const degree = computed(() =>
|
||||
6 - (currentTrack.value / trackCount.value * (30) - 12)
|
||||
);
|
||||
const rotate = ref(0);
|
||||
const cssVars = computed(() => {
|
||||
// console.log({"--rotate": `${rotate.value}deg`});
|
||||
return ({"--rotate": `${rotate.value}deg`});
|
||||
});
|
||||
const trackDelta = computed(() => {
|
||||
let start = trackFromIndex.value === -1 ? startTrack.value : operations.value[trackFromIndex.value].track;
|
||||
let end = trackToIndex.value === -1 ? startTrack.value : operations.value[trackToIndex.value].track;
|
||||
return end - start;
|
||||
});
|
||||
const selectTrackSum = computed(()=>{
|
||||
if(selectTrackFromIndex.value === selectTrackToIndex.value)
|
||||
return 0;
|
||||
let t = 0;
|
||||
let last = selectTrackFromIndex.value === -1? selectTrackToIndex.value: operations.value[selectTrackFromIndex.value].track;
|
||||
console.log(selectTrackFromIndex.value,selectTrackToIndex.value,t);
|
||||
for(let i = Math.max(0,selectTrackFromIndex.value);i<=selectTrackToIndex.value;i++)
|
||||
{
|
||||
console.log(operations.value[i].track);
|
||||
t += Math.abs(operations.value[i].track - last);
|
||||
last = operations.value[i].track;
|
||||
}
|
||||
return t;
|
||||
})
|
||||
|
||||
let token: number = -1;
|
||||
watch(degree, (newDeg) => {
|
||||
if (token !== -1) {
|
||||
clearInterval(token);
|
||||
}
|
||||
let state = 0;
|
||||
let start = rotate.value;
|
||||
let end = newDeg;
|
||||
let v = 0;
|
||||
//a = 2x/t^2 = 2 * ((end - start) / 2) / (duration / 2) / (duration / 2)
|
||||
// = 2 * (end - start) / duration^2
|
||||
let a = 4 * (end - start) / duration / duration;
|
||||
token = setInterval(() => {
|
||||
// console.log(rotate.value);
|
||||
v = v + a * duration / animationCount * (state >= animationCount / 2 ? -1 : 1);
|
||||
state++;
|
||||
rotate.value = rotate.value + v * duration / animationCount;
|
||||
// console.log(state);
|
||||
if (state >= animationCount) {
|
||||
rotate.value = end;
|
||||
clearInterval(token);
|
||||
token = -1;
|
||||
}
|
||||
}, duration / animationCount * 1000);
|
||||
}, {immediate: true});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="disk">
|
||||
<t-image src="/src/assets/Disk.png" fit="cover" :style="{ width: '470px', height: '487px' }" position="right"/>
|
||||
<div id="pin" :style="cssVars">
|
||||
<t-image :key="cssVars" src="/src/assets/Pin.png" fit="cover"
|
||||
:style="{ width: '206px', height: '240px', background: 'transparent' }"
|
||||
position="right"/>
|
||||
</div>
|
||||
<div id="track-delta">
|
||||
<t-typography-text style="color:#cccaff;">{{
|
||||
trackDelta === 0 ? 0 : (trackDelta > 0 ? '+' + trackDelta : trackDelta)
|
||||
}}
|
||||
</t-typography-text>
|
||||
</div>
|
||||
<div id="track-sum">
|
||||
<t-typography-text style="color:#cccaff;">Sum: {{ selectTrackSum }}
|
||||
</t-typography-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
#disk {
|
||||
width: 470px;
|
||||
height: 487px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#disk::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-shadow: inset 0px -20px 15px -12px #242424,
|
||||
inset 0px 20px 15px -12px #242424;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
@rotate: var(--rotate, 0deg);
|
||||
|
||||
#pin {
|
||||
position: absolute;
|
||||
top: 218px;
|
||||
left: 150px;
|
||||
z-index: 1;
|
||||
transform-origin: 50px 191px;
|
||||
rotate: @rotate;
|
||||
}
|
||||
|
||||
#track-delta {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 396px;
|
||||
left: 210px;
|
||||
}
|
||||
#track-sum {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 396px;
|
||||
left: 270px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,76 @@
|
|||
<script setup lang="ts">
|
||||
import * as echarts from 'echarts';
|
||||
import {computed, onMounted, ref, watch} from 'vue';
|
||||
import {storeToRefs} from 'pinia';
|
||||
import useExpr2Store from '@/store/expr2/expr2Store.ts';
|
||||
|
||||
const chartRef = ref(null);
|
||||
const expr2Store = useExpr2Store();
|
||||
const {operations, dataChanged,startTrack} = storeToRefs(expr2Store);
|
||||
let opers = computed(()=>[{track: startTrack.value, time: 0},...operations.value]);
|
||||
onMounted(() => {
|
||||
const chart = echarts.init(chartRef.value);
|
||||
const option = {
|
||||
title: {
|
||||
text: ' Mechanical Hard Drive Seek Time Diagram'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (params: { data: number[] }[]) => {
|
||||
const {data} = params[0];
|
||||
return `Time: ${data[1]}<br/>Track: ${data[0]}`;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
name: 'Track',
|
||||
position: 'top',
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: 'Time',
|
||||
inverse: true,
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
symbol: ['arrow', 'none']
|
||||
}
|
||||
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: opers.value.map((operation, index) => [operation.track, index]),
|
||||
type: 'line',
|
||||
smooth: false
|
||||
}
|
||||
]
|
||||
};
|
||||
chart.setOption(option);
|
||||
watch(dataChanged, (newVal) => {
|
||||
if (newVal === false)
|
||||
return;
|
||||
chart.setOption(({
|
||||
series: [
|
||||
{
|
||||
data: opers.value.map((operation, index) => [operation.track, index]),
|
||||
type: 'line',
|
||||
smooth: false
|
||||
}
|
||||
]
|
||||
}));
|
||||
dataChanged.value = false;
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="chartRef" style="width: 600px; height: 400px;"></div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
|
@ -0,0 +1,208 @@
|
|||
<script setup lang="tsx">
|
||||
|
||||
import {storeToRefs} from "pinia";
|
||||
import {Input} from "tdesign-vue-next";
|
||||
import {computed} from "vue";
|
||||
import useExpr2Store from "@/store/expr2/expr2Store.ts";
|
||||
import {Operation} from "@/store/expr2/defaultOperation.ts";
|
||||
|
||||
let expr2Store = useExpr2Store();
|
||||
let {
|
||||
startTrack,
|
||||
operations,
|
||||
originOperations,
|
||||
tableChanged,
|
||||
currentTrack,
|
||||
trackFromIndex,
|
||||
trackToIndex,
|
||||
selectTrackFromIndex,
|
||||
selectTrackToIndex
|
||||
} = storeToRefs(expr2Store);
|
||||
let data = computed(() => {
|
||||
console.log(startTrack.value);
|
||||
return [{track: startTrack.value, id: 0}, ...operations.value].map((operation: Operation, index: number) => {
|
||||
return {
|
||||
key: String(index + 1),
|
||||
id: operation.id,
|
||||
track: operation.track,
|
||||
}
|
||||
});
|
||||
});
|
||||
let beforeKey = -1;
|
||||
let beforeFromKey = -1;
|
||||
let beforeToKey = -1;
|
||||
|
||||
function FindOriginOperationIndex(key: string): number {
|
||||
let index = parseInt(key) - 1;
|
||||
index = data.value[index].id;
|
||||
console.log("index", index)
|
||||
if (index === 0)
|
||||
return -1;
|
||||
for (let i = 0; i < originOperations.value.length; i++) {
|
||||
if (originOperations.value[i].id === index)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function OnTableBlur(col: number, {key: editedRowKey}: { key: string }, value: number | string) {
|
||||
console.log(editedRowKey);
|
||||
let index = FindOriginOperationIndex(editedRowKey);
|
||||
console.log(index, col, value)
|
||||
if (index === -1) {
|
||||
if (col === 2) {
|
||||
startTrack.value = value as number;
|
||||
tableChanged.value = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (col) {
|
||||
case 1:
|
||||
originOperations.value[index].id = value as number;
|
||||
break;
|
||||
case 2:
|
||||
originOperations.value[index].track = value as number;
|
||||
break;
|
||||
}
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
colKey: 'key'
|
||||
},
|
||||
{
|
||||
title: '任务编号',
|
||||
colKey: 'id',
|
||||
edit: {
|
||||
component: Input,
|
||||
props: {
|
||||
clearable: true,
|
||||
autofocus: true,
|
||||
autoWidth: true,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
{
|
||||
pattern: /^\d+$/,
|
||||
message: '请输入数字',
|
||||
}],
|
||||
on: ({colIndex, editedRow}: {
|
||||
colIndex: number,
|
||||
editedRow: { key: string }
|
||||
}) => ({
|
||||
onBlur: (value: number) => OnTableBlur(colIndex, editedRow, value)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '目标磁道',
|
||||
colKey: 'track',
|
||||
edit: {
|
||||
component: Input,
|
||||
props: {
|
||||
clearable: true,
|
||||
autofocus: true,
|
||||
autoWidth: true,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
{
|
||||
pattern: /^\d+$/,
|
||||
message: '请输入数字',
|
||||
}],
|
||||
on: ({colIndex, editedRow}: {
|
||||
colIndex: number,
|
||||
editedRow: { key: string }
|
||||
}) => ({
|
||||
onBlur: (value: number) => OnTableBlur(colIndex, editedRow, value)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
colKey: 'operation',
|
||||
title: '操作',
|
||||
width: 140
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
function MouseEnter({row, index}: { row: { track: number }, index: number }) {
|
||||
beforeKey = currentTrack.value;
|
||||
beforeFromKey = trackFromIndex.value;
|
||||
beforeToKey = trackToIndex.value;
|
||||
currentTrack.value = row.track;
|
||||
trackFromIndex.value = Math.max(-1, index - 2);
|
||||
trackToIndex.value = index - 1;
|
||||
}
|
||||
|
||||
function MouseLeave() {
|
||||
currentTrack.value = beforeKey;
|
||||
}
|
||||
|
||||
// function MouseClick({row}: { row: { track: number } }) {
|
||||
// currentTrack.value = -1;
|
||||
// beforeKey = row.track;
|
||||
// currentTrack.value = beforeKey;
|
||||
// }
|
||||
function ActiveChange(rows: string[]) {
|
||||
console.log(rows);
|
||||
if (rows.length === 0)
|
||||
return;
|
||||
selectTrackFromIndex.value = parseInt(rows[0]) - 2;
|
||||
selectTrackToIndex.value = parseInt(rows[rows.length - 1]) - 2;
|
||||
}
|
||||
|
||||
// row Error
|
||||
function InsertBefore(row: number) {
|
||||
originOperations.value.splice(row - 1, 0, {
|
||||
id: 0,
|
||||
track: -1
|
||||
});
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
function InsertEnd() {
|
||||
originOperations.value.push({
|
||||
id: 0,
|
||||
track: -1
|
||||
});
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
// row Error
|
||||
function Delete(row: number) {
|
||||
originOperations.value.splice(row - 1, 1);
|
||||
tableChanged.value = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="operations">
|
||||
<t-table row-key="key" :columns="columns" :data="data" :hover="true"
|
||||
:resizable=true @row-mouseenter="MouseEnter" @row-mouseleave="MouseLeave" @active-change="ActiveChange"
|
||||
:column-controller="{displayType: 'auto-width',hideTriggerButton: true}" :active-row-type="'single'">
|
||||
<template #operation="{ row }">
|
||||
<t-link style="display: inline" theme="primary" hover="color" @click="InsertBefore(parseInt(row.key))">
|
||||
在之前插入
|
||||
</t-link>
|
||||
<t-link theme="primary" hover="color" @click.stop="Delete(parseInt(row.key))">
|
||||
删除
|
||||
</t-link>
|
||||
</template>
|
||||
</t-table>
|
||||
<t-button @click="InsertEnd">新增一条操作</t-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
|
@ -0,0 +1,206 @@
|
|||
import {Ref, ref, watch} from "vue";
|
||||
import useExpr1Store from "@/store/expr1/expr1Store.ts";
|
||||
import {storeToRefs} from "pinia";
|
||||
import {Operation} from "@/store/expr1/defaultOperation.ts";
|
||||
|
||||
export enum Selector {
|
||||
FirstFit,
|
||||
BestFit,
|
||||
WorstFit
|
||||
}
|
||||
|
||||
export class Ram {
|
||||
_memSize: Ref<number, number>;
|
||||
_memory: Ref<Block[], Block[]>;
|
||||
_operations: Ref<Operation[], Operation[]>;
|
||||
_selectors: ((operation: Operation) => number)[];
|
||||
_currentSelector: number = 0;
|
||||
_nextOperation: number = 0;
|
||||
_currentState: Ref<number, number>;
|
||||
_allStates: Ref<Block[][], Block[][]> = ref([]);
|
||||
_releaseHistory: Map<number, number>
|
||||
|
||||
static OperationToProcess(operation: Operation): Block {
|
||||
return new Block(operation.id, operation.memorySize);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
let store = useExpr1Store();
|
||||
let {operations, memSize, tableChanged} = storeToRefs(store);
|
||||
this._operations = operations;
|
||||
this._memSize = memSize;
|
||||
this._memory = ref([new Block(0, memSize.value, "Space")]);
|
||||
this._selectors = [this.FirstFit.bind(this), this.BestFit.bind(this), this.WorstFit.bind(this)];
|
||||
this._currentState = storeToRefs(store).currentState;
|
||||
this._allStates.value.push(this._memory.value.map(x => x));
|
||||
this._releaseHistory = new Map();
|
||||
let {failInfo} = storeToRefs(store);
|
||||
while (this._nextOperation < operations.value.length) {
|
||||
this.Process();
|
||||
this._allStates.value.push(this._memory.value.map(x => Block.Clone(x)));
|
||||
}
|
||||
watch(tableChanged, (val) => {
|
||||
if (!val)
|
||||
return;
|
||||
this._nextOperation = 0;
|
||||
this._allStates.value = [];
|
||||
failInfo.value = "";
|
||||
this._releaseHistory = new Map();
|
||||
this._memory.value = [new Block(0, memSize.value, "Space")];
|
||||
this._allStates.value.push(this._memory.value.map(x => Block.Clone(x)));
|
||||
while (this._nextOperation < this._operations.value.length) {
|
||||
try {
|
||||
this.Process();
|
||||
this._allStates.value.push(this._memory.value.map(x => Block.Clone(x)));
|
||||
} catch (e:any) {
|
||||
e = e as Error;
|
||||
console.log(this._nextOperation, e);
|
||||
failInfo.value = "任务" + this._nextOperation + '\t' +e.message;
|
||||
while (this._nextOperation < operations.value.length) {
|
||||
this._allStates.value.push(this._memory.value.map(x => Block.Clone(x)));
|
||||
this._nextOperation++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
tableChanged.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
set CurrentSelector(value: Selector) {
|
||||
this._currentSelector = value;
|
||||
console.log(this._currentSelector);
|
||||
}
|
||||
|
||||
GetMemory() {
|
||||
if (this._currentState.value >= this._allStates.value.length)
|
||||
this._currentState.value = this._allStates.value.length - 1;
|
||||
return this._allStates.value[this._currentState.value];
|
||||
}
|
||||
|
||||
GetReleaseHistory(processID: number) {
|
||||
if (this._releaseHistory.has(processID))
|
||||
return this._releaseHistory.get(processID)!;
|
||||
else
|
||||
return '-';
|
||||
}
|
||||
|
||||
FirstFit(operation: Operation): number {
|
||||
for (let i = 0; i < this._memory.value.length; i++) {
|
||||
if (this._memory.value[i].Type === "Process") {
|
||||
continue;
|
||||
}
|
||||
if (this._memory.value[i].MemorySize >= operation.memorySize) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
BestFit(operation: Operation): number {
|
||||
let memories: Map<number, number> = new Map();
|
||||
for (let i = 0; i < this._memory.value.length; i++) {
|
||||
if (this._memory.value[i].Type === "Process") {
|
||||
continue;
|
||||
}
|
||||
memories.set(i, this._memory.value[i].MemorySize);
|
||||
}
|
||||
let sorted = Array.from(memories).sort((a, b) => a[1] - b[1]);
|
||||
for (let i = 0; i < sorted.length; i++) {
|
||||
if (sorted[i][1] >= operation.memorySize) {
|
||||
return sorted[i][0];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
WorstFit(operation: Operation): number {
|
||||
let memories: Map<number, number> = new Map();
|
||||
for (let i = 0; i < this._memory.value.length; i++) {
|
||||
if (this._memory.value[i].Type === "Process") {
|
||||
continue;
|
||||
}
|
||||
memories.set(i, this._memory.value[i].MemorySize);
|
||||
}
|
||||
let sorted = Array.from(memories).sort((a, b) => b[1] - a[1]);
|
||||
for (let i = 0; i < sorted.length; i++) {
|
||||
if (sorted[i][1] >= operation.memorySize) {
|
||||
return sorted[i][0];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Process() {
|
||||
if (this._nextOperation >= this._operations.value.length)
|
||||
return;
|
||||
let operation = this._operations.value[this._nextOperation];
|
||||
if (operation.type === 'request' && operation.memorySize === 0) {
|
||||
this._nextOperation++;
|
||||
return;
|
||||
}
|
||||
this._nextOperation++;
|
||||
let process = Ram.OperationToProcess(operation);
|
||||
if (operation.type === 'release') {
|
||||
let index = this._memory.value.findIndex((value) => value.Type === "Process" && value.ProcessID == process.ProcessID);
|
||||
if (index == -1) {
|
||||
throw Error("Process not found");
|
||||
}
|
||||
if (process.MemorySize !== this._memory.value[index].MemorySize) {
|
||||
console.warn("Memory size not match");
|
||||
process.MemorySize = this._memory.value[index].MemorySize;
|
||||
}
|
||||
this._releaseHistory.set(process.ProcessID, this._memory.value[index].MemorySize);
|
||||
let space = new Block(this._memory.value[index].ProcessID, process.MemorySize, "Space");
|
||||
space.Start = this._memory.value[index].Start;
|
||||
this._memory.value[index] = space;
|
||||
if (index > 0 && this._memory.value[index - 1].Type === "Space") {
|
||||
let prev = this._memory.value[index - 1];
|
||||
prev.MemorySize += space.MemorySize;
|
||||
this._memory.value.splice(index, 1);
|
||||
index--;
|
||||
space = prev;
|
||||
}
|
||||
if (index < this._memory.value.length - 1 && this._memory.value[index + 1].Type === "Space") {
|
||||
let next = this._memory.value[index + 1];
|
||||
space.MemorySize += next.MemorySize;
|
||||
this._memory.value.splice(index + 1, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let index = this._selectors[this._currentSelector](operation);
|
||||
if (index == -1) {
|
||||
throw Error("No enough memory");
|
||||
}
|
||||
let space = this._memory.value[index];
|
||||
process.Start = space.Start;
|
||||
if (space.MemorySize == process.MemorySize) {
|
||||
this._memory.value.splice(index, 1);
|
||||
} else {
|
||||
space.Start += process.MemorySize;
|
||||
space.MemorySize -= process.MemorySize;
|
||||
}
|
||||
this._memory.value.push(process);
|
||||
this._memory.value.sort((a, b) => a.Start - b.Start);
|
||||
}
|
||||
}
|
||||
|
||||
export class Block {
|
||||
ProcessID = 0;
|
||||
MemorySize = 0;
|
||||
Start = 0;
|
||||
Type: "Process" | "Space" = "Process";
|
||||
|
||||
constructor(processID: number, memorySize: number, type: "Process" | "Space" = "Process") {
|
||||
this.ProcessID = processID;
|
||||
this.MemorySize = memorySize;
|
||||
this.Type = type;
|
||||
}
|
||||
|
||||
static Clone(block: Block) {
|
||||
let newBlock = new Block(block.ProcessID, block.MemorySize, block.Type);
|
||||
newBlock.Start = block.Start;
|
||||
return newBlock;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
import {watch} from "vue";
|
||||
import useExpr2Store from "@/store/expr2/expr2Store.ts";
|
||||
import {storeToRefs} from "pinia";
|
||||
import {Operation} from "@/store/expr2/defaultOperation.ts";
|
||||
|
||||
export enum Algorithm {
|
||||
FCFS,
|
||||
SSTF,
|
||||
SCAN_FirstDown,
|
||||
SCAN_FirstUp
|
||||
}
|
||||
|
||||
export class Disk {
|
||||
constructor() {
|
||||
const {
|
||||
algorithm,
|
||||
operations,
|
||||
originOperations,
|
||||
startTrack,
|
||||
trackCount,
|
||||
failInfo,
|
||||
tableChanged,
|
||||
dataChanged
|
||||
} = storeToRefs(useExpr2Store());
|
||||
watch(tableChanged, (newVal) => {
|
||||
if(newVal === false)
|
||||
return;
|
||||
failInfo.value = "";
|
||||
switch (algorithm.value) {
|
||||
case Algorithm.FCFS:
|
||||
operations.value = originOperations.value.map(x => x);
|
||||
break;
|
||||
case Algorithm.SSTF:
|
||||
operations.value = this.SSTF(originOperations.value.map(x => x), startTrack.value);
|
||||
break;
|
||||
case Algorithm.SCAN_FirstDown:
|
||||
operations.value = this.SCAN(originOperations.value.map(x => x), startTrack.value, false);
|
||||
break;
|
||||
case Algorithm.SCAN_FirstUp:
|
||||
operations.value = this.SCAN(originOperations.value.map(x => x), startTrack.value, true);
|
||||
break;
|
||||
}
|
||||
for (let i = 0; i < operations.value.length; i++) {
|
||||
if (operations.value[i].track < 0 || operations.value[i].track > trackCount.value) {
|
||||
failInfo.value = i + `: track(${operations.value[i].track}) out of range`;
|
||||
}
|
||||
}
|
||||
dataChanged.value = true;
|
||||
tableChanged.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
SSTF(operations: Operation[], startTrack: number): Operation[] {
|
||||
let ans: Operation[] = [];
|
||||
operations.sort((a, b) => a.track - b.track);
|
||||
let set: Set<number> = new Set();
|
||||
|
||||
function FindTrack(): number {
|
||||
let track = startTrack;
|
||||
if (track < operations[0].track)
|
||||
track = 0;
|
||||
else if (track > operations[operations.length - 1].track)
|
||||
track = operations.length - 1;
|
||||
else
|
||||
for (let i = 0; i < operations.length - 1; i++) {
|
||||
if (operations[i].track === track) {
|
||||
track = i;
|
||||
break;
|
||||
} else if (operations[i].track <= track && track <= operations[i + 1].track) {
|
||||
track = track - operations[i].track < operations[i + 1].track - track ? i : i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
let track = FindTrack();
|
||||
ans.push(operations[track])
|
||||
set.add(track);
|
||||
//O(n)
|
||||
while (set.size < operations.length) {
|
||||
let candidate: number[] = [];
|
||||
|
||||
let left = track, right = track;
|
||||
while (left >= 0) {
|
||||
if (set.has(left))
|
||||
left--;
|
||||
else {
|
||||
candidate.push(left);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (right <= operations.length - 1) {
|
||||
if (set.has(right))
|
||||
right++;
|
||||
else {
|
||||
candidate.push(right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let min = Number.MAX_VALUE;
|
||||
for (let t of candidate) {
|
||||
if (Math.abs(operations[t].track - operations[track].track) < min) {
|
||||
min = Math.abs(operations[t].track - operations[track].track);
|
||||
track = t;
|
||||
}
|
||||
}
|
||||
ans.push(operations[track]);
|
||||
set.add(track);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
SCAN(operations: Operation[], startTrack: number, direction: boolean): Operation[] {
|
||||
let ans: Operation[] = [];
|
||||
operations.sort((a, b) => a.track - b.track);
|
||||
let track;
|
||||
|
||||
if(direction)
|
||||
track = operations.findIndex(x => x.track >= startTrack);
|
||||
else
|
||||
track = operations.length - 1 - operations.slice().reverse().findIndex(x => x.track <= startTrack);
|
||||
if(track === -1)
|
||||
track = operations.length - 1;
|
||||
if(track === operations.length)
|
||||
track = 0;
|
||||
startTrack = track;
|
||||
ans.push(operations[track]);
|
||||
while (track + (direction ? 1 : -1) >= 0 && track + (direction ? 1 : -1) < operations.length) {
|
||||
track += (direction) ? 1 : -1;
|
||||
ans.push(operations[track]);
|
||||
}
|
||||
track = startTrack;
|
||||
while (track + (direction ? -1 : 1) >= 0 && track + (direction ? -1 : 1) < operations.length) {
|
||||
track += (direction) ? -1 : 1;
|
||||
ans.push(operations[track]);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { createApp } from 'vue'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
import router from './router.ts'
|
||||
import TDesign from 'tdesign-vue-next'
|
||||
import 'tdesign-vue-next/es/style/index.css'
|
||||
import {createPinia} from "pinia";
|
||||
document.documentElement.setAttribute('theme-mode', 'dark');
|
||||
createApp(App)
|
||||
.use(router)
|
||||
.use(TDesign)
|
||||
.use(createPinia())
|
||||
.mount('#app')
|
|
@ -0,0 +1,19 @@
|
|||
import {createRouter, createWebHashHistory} from 'vue-router'
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/expr1'
|
||||
},
|
||||
{
|
||||
path: '/expr1',
|
||||
component: () => import('@/components/expr1.vue')
|
||||
},
|
||||
{
|
||||
path: '/expr2',
|
||||
component: () => import('@/components/expr2.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
export default router;
|
|
@ -0,0 +1,20 @@
|
|||
const operations: Operation[] = [
|
||||
{ id: 1, memorySize: 200, type: 'request' },
|
||||
{ id: 2, memorySize: 200, type: 'request' },
|
||||
{ id: 3, memorySize: 300, type: 'request' },
|
||||
{ id: 4, memorySize: 200, type: 'request' },
|
||||
{ id: 5, memorySize: 100, type: 'request' },
|
||||
{ id: 1, memorySize: 200, type: 'release' },
|
||||
{ id: 3, memorySize: 300, type: 'release' },
|
||||
{ id: 5, memorySize: 100, type: 'release' },
|
||||
{ id: 6, memorySize: 50, type: 'request' },
|
||||
// { id: 4, memorySize: 450, type: 'release' },
|
||||
// { id: 5, memorySize: 500, type: 'request' },
|
||||
// { id: 5, memorySize: 550, type: 'release' },
|
||||
];
|
||||
export default operations;
|
||||
export interface Operation {
|
||||
id: number;
|
||||
memorySize: number;
|
||||
type: 'request' | 'release';
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import {defineStore} from "pinia";
|
||||
import operations from '@/store/expr1/defaultOperation.ts'
|
||||
|
||||
const useExpr1Store = defineStore('expr1', {
|
||||
state: () => ({
|
||||
operations: operations,
|
||||
memSize: 1000,
|
||||
detailMemoryIndex: -1,
|
||||
currentState: operations.length,
|
||||
tableChanged: false,
|
||||
failInfo: ''
|
||||
}),
|
||||
getters: {},
|
||||
actions: {}
|
||||
})
|
||||
export default useExpr1Store;
|
|
@ -0,0 +1,17 @@
|
|||
const operations: Operation[] = [
|
||||
{id: 1, track: 80},
|
||||
{id: 2, track: 60},
|
||||
{id: 3, track: 90},
|
||||
{id: 4, track: 70},
|
||||
{id: 5, track: 10},
|
||||
{id: 6, track: 30},
|
||||
{id: 7, track: 20},
|
||||
{id: 8, track: 99},
|
||||
{id: 9, track: 50},
|
||||
];
|
||||
export default operations;
|
||||
|
||||
export interface Operation {
|
||||
id: number;
|
||||
track: number;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import {defineStore} from "pinia";
|
||||
import operations from "@/store/expr2/defaultOperation.ts";
|
||||
import {Algorithm} from "@/logical/expr2/disk.ts";
|
||||
|
||||
|
||||
const useExpr2Store = defineStore('expr2', {
|
||||
state: () => ({
|
||||
trackCount: 100,
|
||||
currentTrack: 0,
|
||||
startTrack: 50,
|
||||
operations: operations,
|
||||
originOperations: operations,
|
||||
tableChanged: false,
|
||||
dataChanged: false,
|
||||
algorithm: Algorithm.FCFS,
|
||||
failInfo: "",
|
||||
trackFromIndex: 0,
|
||||
trackToIndex: 0,
|
||||
selectTrackFromIndex: 0,
|
||||
selectTrackToIndex: 0
|
||||
}),
|
||||
getters: {},
|
||||
actions: {}
|
||||
})
|
||||
export default useExpr2Store;
|
|
@ -0,0 +1,26 @@
|
|||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "vue",
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue(),
|
||||
vueJsx()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': '/src'
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue