Compare commits

...

4 commits

Author SHA1 Message Date
d543ebc174 Implemented lrucache 2024-06-05 03:46:41 +03:00
c0293f8599 Implemented otp 2024-06-05 01:34:01 +03:00
63dc763245 Implemented forth 2024-06-05 00:10:25 +03:00
79bb3b15d7 Improved speller readability 2024-06-04 17:26:02 +03:00
4 changed files with 292 additions and 33 deletions

View file

@ -2,17 +2,173 @@
package main
import (
"errors"
"strconv"
"strings"
)
type Evaluator struct {
stack []int
words map[string](func() error)
}
func (e *Evaluator) push(n int) {
e.stack = append(e.stack, n)
}
func (e *Evaluator) pop() (int, error) {
size := len(e.stack)
if size == 0 {
return 0, errors.New("nothing to pop")
}
n := e.stack[size-1]
e.stack = e.stack[:size-1]
return n, nil
}
func (e *Evaluator) popTwo() (int, int, error) {
if len(e.stack) < 2 {
return 0, 0, errors.New("not enough elements on stack")
}
second, _ := e.pop()
first, _ := e.pop()
return first, second, nil
}
// Used to initialzie arithemtic operations in words map
func (e *Evaluator) arithmeticOp(op func(int, int) int) func() error {
return func() error {
a, b, err := e.popTwo()
if err != nil {
return errors.New("not enough elements on stack")
}
e.push(op(a, b))
return nil
}
}
func (e *Evaluator) initBasicWords() {
e.words["+"] = e.arithmeticOp(func(a, b int) int { return a + b })
e.words["-"] = e.arithmeticOp(func(a, b int) int { return a - b })
e.words["*"] = e.arithmeticOp(func(a, b int) int { return a * b })
e.words["/"] = func() error {
a, b, err := e.popTwo()
if err != nil {
return errors.New("not enough elements on stack")
}
if b == 0 {
return errors.New("division by zero")
}
e.push(a / b)
return nil
}
e.words["dup"] = func() error {
size := len(e.stack)
if size == 0 {
return errors.New("not enough elements on stack")
}
e.stack = append(e.stack, e.stack[size-1])
return nil
}
e.words["over"] = func() error {
size := len(e.stack)
if size < 2 {
return errors.New("not enough elements on stack")
}
e.stack = append(e.stack, e.stack[size-2])
return nil
}
e.words["drop"] = func() error {
_, err := e.pop()
return err
}
e.words["swap"] = func() error {
size := len(e.stack)
if size < 2 {
return errors.New("not enough elements on stack")
}
e.stack[size-1], e.stack[size-2] = e.stack[size-2], e.stack[size-1]
return nil
}
}
func (e *Evaluator) getFunc(word string) (func() error, error) {
call, found := e.words[word]
if found {
return call, nil
}
num, err := strconv.Atoi(word)
if err != nil {
return nil, errors.New("word is not numerical or is not defined")
}
call = func() error {
e.push(num)
return nil
}
return call, nil
}
func (e *Evaluator) defineWord(word string, def string) error {
_, err := strconv.Atoi(word)
if err == nil {
return errors.New("word definition must not be numeric")
}
definitionWords := strings.Fields(def)
callChain := make([](func() error), len(definitionWords))
for i, w := range definitionWords {
call, err := e.getFunc(w)
if err != nil {
return err
}
callChain[i] = call
}
e.words[word] = func() error {
for _, call := range callChain {
err := call()
if err != nil {
return err
}
}
return nil
}
return nil
}
// NewEvaluator creates evaluator.
func NewEvaluator() *Evaluator {
return &Evaluator{}
eval := &Evaluator{make([]int, 0), make(map[string](func() error))}
eval.initBasicWords()
return eval
}
// Process evaluates sequence of words or definition.
//
// Returns resulting stack state and an error.
func (e *Evaluator) Process(row string) ([]int, error) {
return nil, nil
row = strings.ToLower(row)
if strings.HasPrefix(row, ":") && strings.HasSuffix(row, ";") {
row = strings.Trim(row, " :;")
wordAndDef := strings.SplitN(row, " ", 2)
if len(wordAndDef) < 2 {
return e.stack, errors.New("couldn't define a new word - incorrect syntax")
}
word, def := wordAndDef[0], wordAndDef[1]
err := e.defineWord(word, def)
if err != nil {
return e.stack, err
}
return e.stack, nil
}
for _, word := range strings.Fields(row) {
call, err := e.getFunc(word)
if err != nil {
return e.stack, err
}
err = call()
if err != nil {
return e.stack, err
}
}
return e.stack, nil
}

View file

@ -2,6 +2,68 @@
package lrucache
func New(cap int) Cache {
panic("implement me")
import (
"container/list"
)
type cacheEntry struct {
key int
value int
}
type lrucache struct {
cap int
data map[int]*list.Element
recentEntries *list.List
}
func (c *lrucache) isFull() bool {
return c.recentEntries.Len() == c.cap
}
func (c *lrucache) Get(key int) (int, bool) {
e, ok := c.data[key]
if !ok {
return 0, false
}
entry := c.recentEntries.Remove(e).(cacheEntry)
c.data[key] = c.recentEntries.PushBack(entry)
return entry.value, true
}
func (c *lrucache) Set(key int, value int) {
if c.cap == 0 {
return
}
e, ok := c.data[key]
if ok {
c.recentEntries.Remove(e)
c.data[key] = c.recentEntries.PushBack(cacheEntry{key, value})
return
}
if c.isFull() {
removed := c.recentEntries.Remove(c.recentEntries.Front()).(cacheEntry)
delete(c.data, removed.key)
}
c.data[key] = c.recentEntries.PushBack(cacheEntry{key, value})
}
func (c *lrucache) Range(f func(key, value int) bool) {
for e := c.recentEntries.Front(); e != nil; e = e.Next() {
entry := e.Value.(cacheEntry)
if !f(entry.key, entry.value) {
return
}
}
}
func (c *lrucache) Clear() {
for k := range c.data {
delete(c.data, k)
}
c.recentEntries.Init()
}
func New(cap int) Cache {
return &lrucache{cap, make(map[int]*list.Element), list.New()}
}

View file

@ -6,10 +6,53 @@ import (
"io"
)
type cipherReader struct {
r io.Reader
prng io.Reader
}
type cipherWriter struct {
w io.Writer
prng io.Reader
}
func (c *cipherReader) Read(p []byte) (n int, err error) {
n, err = c.r.Read(p)
if err != nil {
if err == io.EOF {
p = p[:n]
} else {
return
}
}
rand := make([]byte, n)
_, rngErr := c.prng.Read(rand)
if rngErr != nil {
return
}
for i := 0; i < n; i++ {
p[i] ^= rand[i]
}
return
}
func (c *cipherWriter) Write(p []byte) (n int, err error) {
data := make([]byte, len(p))
_, err = c.prng.Read(data)
if err != nil {
return
}
for i := 0; i < len(p); i++ {
data[i] ^= p[i]
}
n, err = c.w.Write(data)
return
}
func NewReader(r io.Reader, prng io.Reader) io.Reader {
panic("implement me")
return &cipherReader{r, prng}
}
func NewWriter(w io.Writer, prng io.Reader) io.Writer {
panic("implement me")
return &cipherWriter{w, prng}
}

View file

@ -6,7 +6,7 @@ import (
"strings"
)
var numToDigits = []string{
var digits = []string{
"", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine",
}
@ -41,48 +41,46 @@ func Spell(n int64) string {
if sign {
n = -n
}
num, digits := strings.Builder{}, digitsReversedSlice(n)
num, numDigits := strings.Builder{}, digitsReversedSlice(n)
// 35 is the optimal number which gives approx needed
// space for the number in 1 allocation
num.Grow(len(digits) * 35)
num.Grow(len(numDigits) * 35)
if sign {
num.WriteString("minus ")
}
largeIndex, iters := 0, 0
for i := len(digits) - 1; i >= 0; i, largeIndex = i-3, largeIndex+1 {
first, second, third := digits[i-2], digits[i-1], digits[i]
if first == 0 && second == 0 && third == 0 {
for i, largeIndex := len(numDigits)-1, 0; i >= 0; i, largeIndex = i-3, largeIndex+1 {
hundreds, tens, ones := numDigits[i], numDigits[i-1], numDigits[i-2]
hundredsPresent, tensPesent, onesPresent := hundreds != 0, tens != 0, ones != 0
if !hundredsPresent && !tensPesent && !onesPresent {
continue
}
if iters != 0 {
num.WriteRune(' ')
}
hundreds := numToDigits[third]
if hundreds != "" {
num.WriteString(hundreds)
if hundredsPresent {
num.WriteString(digits[hundreds])
num.WriteString(" hundred")
if second != 0 || first != 0 {
if tensPesent || onesPresent {
num.WriteRune(' ')
}
}
if second > 1 {
num.WriteString(decs[second])
if first > 0 {
num.WriteRune('-')
num.WriteString(numToDigits[first])
}
} else if second == 1 {
num.WriteString(teens[first])
if tensPesent {
if tens == 1 {
num.WriteString(teens[ones])
} else {
if first > 0 {
num.WriteString(numToDigits[first])
num.WriteString(decs[tens])
if onesPresent {
num.WriteRune('-')
}
}
}
if onesPresent && tens != 1 {
num.WriteString(digits[ones])
}
if largeIndex < len(large) {
num.WriteRune(' ')
num.WriteString(large[largeIndex])
}
iters++
num.WriteRune(' ')
}
return num.String()
output := num.String()
output = output[:len(output)-1]
return output
}