Skip to content

Instantly share code, notes, and snippets.

@EmilyGraceSeville7cf
Created March 3, 2024 13:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EmilyGraceSeville7cf/de6eb89986a40a5ccaa2e5d40da6cad4 to your computer and use it in GitHub Desktop.
Save EmilyGraceSeville7cf/de6eb89986a40a5ccaa2e5d40da6cad4 to your computer and use it in GitHub Desktop.
Linked list based stack
package main
import (
"errors"
"fmt"
"os"
"github.com/fatih/color"
)
type Node[T any] struct {
value T
next *Node[T]
}
type Stack[T any] struct {
head *Node[T]
count int
}
func nilValueMessage(name string) string {
return fmt.Sprintf("not nil %s expected", name)
}
func emptyDataStructureMessage(name string) string {
return fmt.Sprintf("not empty %s expected", name)
}
func lessThanMessage(limit int, name string) string {
return fmt.Sprintf("not less than %d %s expected", limit, name)
}
func newNode[T any](value T) *Node[T] {
return &Node[T]{value: value}
}
func newNodeWithNext[T any](value T, next *Node[T]) *Node[T] {
return &Node[T]{value: value, next: next}
}
func newStack[T any]() *Stack[T] {
return &Stack[T]{count: 0}
}
func (stack *Stack[T]) push(value T) error {
stack.head = newNodeWithNext(value, stack.head)
stack.count++
return nil
}
func Default[T any]() T {
return *new(T)
}
func (stack *Stack[T]) pop() (T, error) {
if stack.count == 0 {
return Default[T](), errors.New(emptyDataStructureMessage("stack"))
}
value := stack.head.value
stack.head = stack.head.next
stack.count--
return value, nil
}
func (stack *Stack[T]) peek() (T, error) {
if stack.count == 0 {
return Default[T](), errors.New(emptyDataStructureMessage("stack"))
}
return stack.head.value, nil
}
func (stack *Stack[T]) String() string {
if stack == nil {
return ""
}
current := stack.head
representation := "["
for current != nil {
representation += fmt.Sprint(current.value)
if current.next != nil {
representation += ", "
}
current = current.next
}
representation += "]"
return representation
}
type Handler func(*Stack[string], ...string)
type Command struct {
description string
handler Handler
argumentCount int
}
func newCommand(description string, handler Handler) (*Command, error) {
if handler == nil {
return nil, errors.New(nilValueMessage("handler"))
}
return &Command{description: description, handler: handler}, nil
}
func newCommandWithArgumentCount(description string, handler Handler, argumentCount int) (*Command, error) {
command, err := newCommand(description, handler)
if err != nil {
return nil, err
}
if argumentCount < 0 {
return nil, errors.New(lessThanMessage(0, "argumentCount"))
}
command.argumentCount = argumentCount
return command, nil
}
func handleArguments(args []string) {
var stack = newStack[string]()
pushCommand, _ := newCommandWithArgumentCount("Push new item", func(stack *Stack[string], args ...string) {
stack.push(args[0])
}, 1)
popCommand, _ := newCommandWithArgumentCount("Pop the last added item", func(stack *Stack[string], args ...string) {
stack.pop()
}, 0)
peekCommand, _ := newCommandWithArgumentCount("Peek the last added item", func(stack *Stack[string], args ...string) {
stack.peek()
}, 0)
commands := make(map[string]*Command)
commands["--push"] = pushCommand
commands["--pop"] = popCommand
commands["--peek"] = peekCommand
for i := 0; i < len(args); i++ {
arg := args[i]
command, exists := commands[arg]
if !exists {
color.Red("expected known command %s", arg)
os.Exit(1)
}
var commandArgs []string
for j := 0; j < command.argumentCount; j++ {
i++
if i >= len(args) {
color.Red("expected argument for %s", arg)
os.Exit(1)
}
commandArgs = append(commandArgs, args[i])
}
command.handler(stack, commandArgs...)
color.Red(command.description)
color.Yellow("%s", stack)
}
}
func main() {
var args = os.Args[1:]
if len(args) > 0 {
handleArguments(args)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment