diff --git a/README.md b/README.md index 6f4b50b..ccf6df4 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,4 @@ problems from * [Day 7](https://github.com/vaskoz/dailycodingproblem-go/issues/15) * [Day 8](https://github.com/vaskoz/dailycodingproblem-go/issues/17) * [Day 9](https://github.com/vaskoz/dailycodingproblem-go/issues/19) +* [Day 10](https://github.com/vaskoz/dailycodingproblem-go/issues/21) diff --git a/day10/problem.go b/day10/problem.go new file mode 100644 index 0000000..f9381da --- /dev/null +++ b/day10/problem.go @@ -0,0 +1,60 @@ +package day10 + +import ( + "fmt" + "log" + "sync" + "time" +) + +// Scheduler represents a job scheduler. +type Scheduler struct { + queue chan job + wg sync.WaitGroup + startTime time.Time +} + +type job struct { + f func() + n uint + jobStartTime time.Time +} + +// NewScheduler returns a new instance of a running job scheduler. +func NewScheduler() *Scheduler { + s := &Scheduler{queue: make(chan job), startTime: time.Now()} + s.wg.Add(1) + go func() { + for j := range s.queue { + s.wg.Add(1) + go func(j job) { + ms, _ := time.ParseDuration(fmt.Sprintf("%dms", j.n)) + time.Sleep(ms) + log.Printf("starting job at %dms", convertNanoToMillis(time.Since(s.startTime).Nanoseconds())) + j.f() + log.Printf("completed job at %dms", convertNanoToMillis(time.Since(s.startTime).Nanoseconds())) + s.wg.Done() + }(j) + } + }() + return s +} + +// Schedule schedules a new job to be run. +func (s *Scheduler) Schedule(f func(), millis uint) { + current := convertNanoToMillis(time.Since(s.startTime).Nanoseconds()) + log.Printf("Received at %dms scheduled for %dms", current, current+int64(millis)) + s.queue <- job{f, millis, time.Now()} +} + +// Shutdown prevents new jobs from being scheduled and allows the scheduler to terminate. +func (s *Scheduler) Shutdown() { + close(s.queue) + s.wg.Done() + s.wg.Wait() + log.Printf("Scheduler shutdown complete at %dms", convertNanoToMillis(time.Since(s.startTime).Nanoseconds())) +} + +func convertNanoToMillis(duration int64) int64 { + return duration / int64(1000000) +} diff --git a/day10/problem_test.go b/day10/problem_test.go new file mode 100644 index 0000000..abebfad --- /dev/null +++ b/day10/problem_test.go @@ -0,0 +1,30 @@ +package day10 + +import ( + "fmt" + "testing" + "time" +) + +func TestScheduler(t *testing.T) { + t.Parallel() + sched := NewScheduler() + sched.Schedule(func() { fmt.Println("hi there") }, 10) + sched.Schedule(func() { fmt.Println("hello there") }, 20) + sched.Schedule(func() { fmt.Println("so long") }, 30) + sched.Schedule(func() { time.Sleep(1 * time.Second); fmt.Println("i fell asleep") }, 1) + sched.Shutdown() +} + +func TestSchedulerParallel(t *testing.T) { + t.Parallel() + sched := NewScheduler() + sched.Schedule(func() { fmt.Println("hi there") }, 10) + sched.Schedule(func() { fmt.Println("hello there") }, 20) + sched.Schedule(func() { fmt.Println("so long") }, 30) + sched.Schedule(func() { time.Sleep(2 * time.Second); fmt.Println("i fell asleep again") }, 1) + time.Sleep(2 * time.Second) + sched.Schedule(func() { fmt.Println("later jobs") }, 1) + sched.Schedule(func() { fmt.Println("later still") }, 10) + sched.Shutdown() +} diff --git a/day7/problem_test.go b/day7/problem_test.go index 472f85d..076ab91 100644 --- a/day7/problem_test.go +++ b/day7/problem_test.go @@ -13,6 +13,7 @@ var testcases = []struct { } func TestNumberOfDecodings(t *testing.T) { + t.Parallel() for _, tc := range testcases { if result := NumberOfDecodings(tc.input); result != tc.expected { t.Errorf("For input %v, expected %v but got %v", tc.input, tc.expected, result) diff --git a/day8/problem_test.go b/day8/problem_test.go index 2974769..80376a0 100644 --- a/day8/problem_test.go +++ b/day8/problem_test.go @@ -3,6 +3,7 @@ package day8 import "testing" func TestCountUnivalSubtrees(t *testing.T) { + t.Parallel() root := &BinaryTree{value: 0, left: &BinaryTree{value: 1}, right: &BinaryTree{value: 0, diff --git a/day9/problem_test.go b/day9/problem_test.go index 0c7cb21..6e15f25 100644 --- a/day9/problem_test.go +++ b/day9/problem_test.go @@ -12,6 +12,7 @@ var testcases = []struct { } func TestMaximumNonAdjacentSum(t *testing.T) { + t.Parallel() for _, tc := range testcases { if result := MaximumNonAdjacentSum(tc.input); result != tc.expected { t.Errorf("Expected %v, but got %v", tc.expected, result)