mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-14 22:18:46 +00:00
Add assignment 11
This commit is contained in:
33
scripts/grade-11.sh
Executable file
33
scripts/grade-11.sh
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -uo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
# Imports library.
|
||||||
|
BASEDIR=$(dirname "$0")
|
||||||
|
source $BASEDIR/grade-utils.sh
|
||||||
|
|
||||||
|
RUNNERS=(
|
||||||
|
"cargo"
|
||||||
|
"cargo --release"
|
||||||
|
"cargo_asan"
|
||||||
|
"cargo_asan --release"
|
||||||
|
"cargo_tsan"
|
||||||
|
"cargo_tsan --release"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Lints.
|
||||||
|
run_linters || exit 1
|
||||||
|
|
||||||
|
# Executes test for each runner.
|
||||||
|
for RUNNER in "${RUNNERS[@]}"; do
|
||||||
|
echo "Running with $RUNNER..."
|
||||||
|
|
||||||
|
TESTS=("--lib assignment11_grade")
|
||||||
|
if [ $(run_tests) -ne 0 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -7,3 +7,4 @@ BASEDIR=$(dirname "$0")/..
|
|||||||
mkdir -p $BASEDIR/target
|
mkdir -p $BASEDIR/target
|
||||||
|
|
||||||
zip -rj $BASEDIR/target/assignment04.zip src/assignments/assignment04
|
zip -rj $BASEDIR/target/assignment04.zip src/assignments/assignment04
|
||||||
|
zip -rj $BASEDIR/target/assignment11.zip src/assignments/assignment11
|
||||||
|
|||||||
62
src/assignments/assignment11/linked_list.rs
Normal file
62
src/assignments/assignment11/linked_list.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
//! Singly linked list.
|
||||||
|
//!
|
||||||
|
//! Consult <https://doc.rust-lang.org/book/ch15-01-box.html>.
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
/// Node of the list.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Node<T: Debug> {
|
||||||
|
/// Value of current node.
|
||||||
|
pub value: T,
|
||||||
|
|
||||||
|
/// Pointer to the next node. If it is `None`, there is no next node.
|
||||||
|
pub next: Option<Box<Node<T>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> Node<T> {
|
||||||
|
/// Creates a new node.
|
||||||
|
pub fn new(value: T) -> Self {
|
||||||
|
Self { value, next: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A singly-linked list.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SinglyLinkedList<T: Debug> {
|
||||||
|
/// Head node of the list. If it is `None`, the list is empty.
|
||||||
|
head: Option<Node<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> Default for SinglyLinkedList<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> SinglyLinkedList<T> {
|
||||||
|
/// Creates a new list.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { head: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given node to the front of the list.
|
||||||
|
pub fn push_front(&mut self, value: T) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given node to the back of the list.
|
||||||
|
pub fn push_back(&mut self, value: T) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes and returns the node at the front of the list.
|
||||||
|
pub fn pop_front(&mut self) -> Option<T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes and returns the node at the back of the list.
|
||||||
|
pub fn pop_back(&mut self) -> Option<T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
97
src/assignments/assignment11/mock_storage.rs
Normal file
97
src/assignments/assignment11/mock_storage.rs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
//! Mock storage.
|
||||||
|
//!
|
||||||
|
//! Consult <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects>.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Mock storage.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MockStorage {
|
||||||
|
/// Files stored in the storage.
|
||||||
|
///
|
||||||
|
/// Each entry of the hashmap represents the `(name, size)` of the file.
|
||||||
|
files: RefCell<HashMap<String, usize>>,
|
||||||
|
|
||||||
|
/// Capacity of the storage.
|
||||||
|
///
|
||||||
|
/// The total size of files stored on the storage cannot exceed the capacity.
|
||||||
|
capacity: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MockStorage {
|
||||||
|
/// Creates a new mock storage.
|
||||||
|
pub fn new(capacity: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
files: RefCell::new(HashMap::new()),
|
||||||
|
capacity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for storage object.
|
||||||
|
pub trait Storage {
|
||||||
|
/// Uploads a file. If a file with the same name already exists in the storage, overwrite it.
|
||||||
|
///
|
||||||
|
/// Returns `Err` with insufficient memory size if there is no free space to upload a file.
|
||||||
|
fn upload(&self, name: &str, size: usize) -> Result<(), usize>;
|
||||||
|
|
||||||
|
/// Returns the used memory size of the storage.
|
||||||
|
fn used(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns the capacity of the storage.
|
||||||
|
fn capacity(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Storage for MockStorage {
|
||||||
|
fn upload(&self, name: &str, size: usize) -> Result<(), usize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn used(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capacity(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// File uploader.
|
||||||
|
///
|
||||||
|
/// It uploads files to the internal storage.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FileUploader<'a, T: Storage> {
|
||||||
|
storage: &'a T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Storage> FileUploader<'a, T> {
|
||||||
|
/// Creates a new file uploader with given internal storage.
|
||||||
|
pub fn new(storage: &'a T) -> Self {
|
||||||
|
Self { storage }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Uploads a file to the internal storage.
|
||||||
|
pub fn upload(&self, name: &str, size: usize) -> Result<(), usize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Storage usage analyzer.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UsageAnalyzer<'a, T: Storage> {
|
||||||
|
storage: &'a T,
|
||||||
|
bound: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Storage> UsageAnalyzer<'a, T> {
|
||||||
|
/// Creates a new usage analyzer.
|
||||||
|
pub fn new(storage: &'a T, bound: f64) -> Self {
|
||||||
|
Self { storage, bound }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the usage of the internal storage is under the bound.
|
||||||
|
pub fn is_usage_under_bound(&self) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/assignments/assignment11/mod.rs
Normal file
9
src/assignments/assignment11/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//! Assignment 11: Familiarizing with smart pointers.
|
||||||
|
//!
|
||||||
|
//! You should fill out `todo!()` placeholders in such a way that `/scripts/grade-11.sh` works fine.
|
||||||
|
//! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script.
|
||||||
|
//! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to <https://gg.kaist.ac.kr>.
|
||||||
|
|
||||||
|
pub mod linked_list;
|
||||||
|
pub mod mock_storage;
|
||||||
|
pub mod tv_room;
|
||||||
108
src/assignments/assignment11/tv_room.rs
Normal file
108
src/assignments/assignment11/tv_room.rs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
//! TV Room Simulator.
|
||||||
|
//!
|
||||||
|
//! People can come to the TV room and watch TV. There are two types of TV watchers, manager and guest.
|
||||||
|
//!
|
||||||
|
//! The rule of the TV room is as follows:
|
||||||
|
//!
|
||||||
|
//! - Closed TV room can be opened by the manager.
|
||||||
|
//! - Guests can enter the TV room by the manager.
|
||||||
|
//! - Manager can leave the TV room earlier than guests.
|
||||||
|
//! - The TV room closes when the last person left the TV room.
|
||||||
|
//!
|
||||||
|
//! Both `Manager` and `Guest` have 'Rc<Watcher>' as a field, and its reference count indicates the number of people in
|
||||||
|
//! the TV room. When the 'Manager' and 'Guest' object is dropped, it means that the person leaves the TV room.
|
||||||
|
//!
|
||||||
|
//! Consult the following documentations:
|
||||||
|
//! - <https://doc.rust-lang.org/book/ch15-04-rc.html#rct-the-reference-counted-smart-pointer>
|
||||||
|
//! - <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#having-multiple-owners-of-mutable-data-by-combining-rct-and-refcellt>
|
||||||
|
|
||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum TVRoomState {
|
||||||
|
Opened,
|
||||||
|
Closed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TV Room
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TVRoom {
|
||||||
|
/// Indicates whether the TV room is state.
|
||||||
|
state: RefCell<TVRoomState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TVRoom {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TVRoom {
|
||||||
|
/// Creates a new TV room.
|
||||||
|
///
|
||||||
|
/// Initial state of the TV room is closed.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
state: RefCell::new(TVRoomState::Closed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Opens the TV room and returns the manager.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the TV room is already opened.
|
||||||
|
pub fn open(&self) -> Option<Manager<'_>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the TV room is opened or not.
|
||||||
|
pub fn is_opened(&self) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TV Room Manager.
|
||||||
|
///
|
||||||
|
/// - The manager is special TV's watcher that has privileges to add other guests.
|
||||||
|
/// - If all watchers including the manager drop (~= leave the TV room), the TV must be turned off.
|
||||||
|
/// - Note that the manager can be dropped while other watchers are watching TV.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Manager<'a> {
|
||||||
|
inner: Rc<Watcher<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Manager<'a> {
|
||||||
|
fn new(tvstate: &'a RefCell<TVRoomState>) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Rc::new(Watcher::new(tvstate)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds new guest to the TV room.
|
||||||
|
pub fn new_guest(&self) -> Guest<'a> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TV Room Guest.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Guest<'a> {
|
||||||
|
inner: Rc<Watcher<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Watcher<'a> {
|
||||||
|
tvstate: &'a RefCell<TVRoomState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Watcher<'a> {
|
||||||
|
fn new(tvstate: &'a RefCell<TVRoomState>) -> Self {
|
||||||
|
Self { tvstate }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Watcher<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// When the last person leaves the TV room, the TV room should be closed.
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
81
src/assignments/assignment11_grade.rs
Normal file
81
src/assignments/assignment11_grade.rs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tv_room() {
|
||||||
|
use crate::assignments::assignment11::tv_room::*;
|
||||||
|
|
||||||
|
let tv_room = TVRoom::new();
|
||||||
|
assert!(!tv_room.is_opened());
|
||||||
|
|
||||||
|
// Turn on and add new guests.
|
||||||
|
let manager = tv_room.open().unwrap();
|
||||||
|
assert!(tv_room.is_opened());
|
||||||
|
let guest1 = manager.new_guest();
|
||||||
|
let guest2 = manager.new_guest();
|
||||||
|
drop(manager);
|
||||||
|
drop(guest1);
|
||||||
|
assert!(tv_room.open().is_none());
|
||||||
|
drop(guest2);
|
||||||
|
assert!(!tv_room.is_opened());
|
||||||
|
|
||||||
|
// Turn on and add new guests.
|
||||||
|
let manager = tv_room.open().unwrap();
|
||||||
|
assert!(tv_room.is_opened());
|
||||||
|
let guest3 = manager.new_guest();
|
||||||
|
drop(guest3);
|
||||||
|
assert!(tv_room.is_opened());
|
||||||
|
drop(manager);
|
||||||
|
assert!(!tv_room.is_opened());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mock_storage() {
|
||||||
|
use crate::assignments::assignment11::mock_storage::*;
|
||||||
|
|
||||||
|
let mock_storage = MockStorage::new(100);
|
||||||
|
|
||||||
|
let uploader1 = FileUploader::new(&mock_storage);
|
||||||
|
let uploader2 = FileUploader::new(&mock_storage);
|
||||||
|
|
||||||
|
let usage_analyzer = UsageAnalyzer::new(&mock_storage, 0.75);
|
||||||
|
|
||||||
|
assert!(uploader1.upload("file1.txt", 20).is_ok());
|
||||||
|
assert!(usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert!(uploader2.upload("file2.txt", 30).is_ok());
|
||||||
|
assert!(usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert!(uploader1.upload("file3.txt", 40).is_ok());
|
||||||
|
assert!(!usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert_eq!(uploader2.upload("file4.txt", 50), Err(40));
|
||||||
|
assert!(!usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert!(uploader1.upload("file3.txt", 10).is_ok());
|
||||||
|
assert!(usage_analyzer.is_usage_under_bound());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct V(usize);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linked_list() {
|
||||||
|
use crate::assignments::assignment11::linked_list::*;
|
||||||
|
|
||||||
|
let mut list = SinglyLinkedList::new();
|
||||||
|
list.push_back(V(3));
|
||||||
|
list.push_front(V(2));
|
||||||
|
list.push_back(V(4));
|
||||||
|
list.push_front(V(1));
|
||||||
|
list.push_back(V(5));
|
||||||
|
|
||||||
|
assert_eq!(list.pop_front(), Some(V(1)));
|
||||||
|
assert_eq!(list.pop_back(), Some(V(5)));
|
||||||
|
assert_eq!(list.pop_front(), Some(V(2)));
|
||||||
|
assert_eq!(list.pop_back(), Some(V(4)));
|
||||||
|
assert_eq!(list.pop_front(), Some(V(3)));
|
||||||
|
assert_eq!(list.pop_back(), None);
|
||||||
|
assert_eq!(list.pop_front(), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,3 +24,5 @@ pub mod assignment09;
|
|||||||
mod assignment09_grade;
|
mod assignment09_grade;
|
||||||
pub mod assignment10;
|
pub mod assignment10;
|
||||||
mod assignment10_grade;
|
mod assignment10_grade;
|
||||||
|
pub mod assignment11;
|
||||||
|
mod assignment11_grade;
|
||||||
|
|||||||
Reference in New Issue
Block a user