Решение на Concurrent Tasks от Марио Даскалов

Обратно към всички решения

Към профила на Марио Даскалов

Резултати

  • 10 точки от тестове
  • 0 бонус точки
  • 10 точки общо
  • 10 успешни тест(а)
  • 0 неуспешни тест(а)

Код

package main
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"sync"
)
type Author struct {
FirstName string `json:"first_name" xml:"first_name"`
LastName string `json:"last_name" xml:"last_name"`
}
func (author Author) String() string {
return author.FirstName + " " + author.LastName
}
type Book struct {
XMLName xml.Name `xml:"book"`
ISBN string `xml:"isbn,attr"`
Title string
Author Author
}
func (book Book) String() string {
return fmt.Sprintf("[%s] %s от %s", book.ISBN, book.Title, book.Author)
}
type LibraryResponse interface {
GetBook() (fmt.Stringer, error)
GetAvailability() (available int, registered int)
}
type Response struct {
book Book
availability int
registered int
err error
}
func (response Response) GetBook() (fmt.Stringer, error) {
if response.err == nil {
return response.book, nil
} else {
return nil, response.err
}
}
func (response Response) GetAvailability() (available int, registered int) {
return response.availability, response.registered
}
type LibraryRequest interface {
GetType() int
GetISBN() string
}
type Librarian struct {
request chan LibraryRequest
response chan LibraryResponse
store LibraryStore
}
type Library interface {
AddBookJSON(data []byte) (int, error)
AddBookXML(data []byte) (int, error)
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryStore struct {
librarians chan Librarian
books map[string][]Book
available map[string]int
lock sync.Mutex
}
func (store LibraryStore) addBook(book Book) (int, error) {
if _, ok := store.books[book.ISBN]; !ok {
store.books[book.ISBN] = []Book{}
store.available[book.ISBN] = 0
}
booksCount := len(store.books[book.ISBN])
if booksCount < 4 {
store.books[book.ISBN] = append(store.books[book.ISBN], book)
store.available[book.ISBN] += 1
return booksCount + 1, nil
} else {
return booksCount, errors.New("Има 4 копия на книга " + book.ISBN)
}
}
func (store LibraryStore) AddBookJSON(data []byte) (int, error) {
var book Book
err := json.Unmarshal(data, &book)
if err != nil {
return 0, err
}
store.lock.Lock()
defer store.lock.Unlock()
return store.addBook(book)
}
func (store LibraryStore) AddBookXML(data []byte) (int, error) {
var book Book
err := xml.Unmarshal(data, &book)
if err != nil {
return 0, err
}
store.lock.Lock()
defer store.lock.Unlock()
return store.addBook(book)
}
func handleBorrow(store LibraryStore, request LibraryRequest) Response {
books, ok := store.books[request.GetISBN()]
availability := store.available[request.GetISBN()]
var response Response
if !ok {
response = Response{err: errors.New("Непозната книга " + request.GetISBN())}
} else if availability == 0 {
response = Response{
registered: len(books),
err: errors.New("Няма наличност на книга " + request.GetISBN())}
} else {
availability -= 1
store.available[request.GetISBN()] = availability
response = Response{
availability: availability,
registered: len(books),
book: books[0],
}
}
return response
}
func handleReturn(store LibraryStore, request LibraryRequest) Response {
books, ok := store.books[request.GetISBN()]
availability := store.available[request.GetISBN()]
var response Response
if !ok {
response = Response{err: errors.New("Непозната книга " + request.GetISBN())}
} else if availability == len(books) {
response = Response{
err: errors.New("Всички копия са налични " + request.GetISBN()),
registered: len(books),
availability: availability,
}
} else {
availability += 1
store.available[request.GetISBN()] = availability
response = Response{
availability: availability,
registered: len(books),
book: books[0],
}
}
return response
}
func handleAvailability(store LibraryStore, request LibraryRequest) Response {
books, ok := store.books[request.GetISBN()]
availability := store.available[request.GetISBN()]
var response Response
if !ok {
response = Response{err: errors.New("Непозната книга " + request.GetISBN())}
} else {
store.available[request.GetISBN()] = availability
response = Response{
availability: availability,
registered: len(books),
book: books[0],
}
}
return response
}
func (store LibraryStore) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
librarian := <-store.librarians
librarian.request = make(chan LibraryRequest)
librarian.response = make(chan LibraryResponse)
go func() {
for request := range librarian.request {
store := librarian.store
store.lock.Lock()
var response Response
switch request.GetType() {
case 1:
response = handleBorrow(store, request)
case 2:
response = handleReturn(store, request)
case 3:
response = handleAvailability(store, request)
}
librarian.response <- response
store.lock.Unlock()
}
store.librarians <- Librarian{}
}()
return librarian.request, librarian.response
}
func NewLibrary(librariansCount int) Library {
store := LibraryStore{
books: make(map[string][]Book),
available: make(map[string]int),
}
librarians := make(chan Librarian, librariansCount)
for i := 0; i < librariansCount; i++ {
librarians <- Librarian{store: store}
}
store.librarians = librarians
return store
}

Лог от изпълнението

PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.003s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.003s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s
PASS
ok  	_/tmp/d20151207-5667-19u08ty	0.004s

История (1 версия и 0 коментара)

Марио обнови решението на 06.12.2015 17:40 (преди над 2 години)

+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "sync"
+)
+
+type Author struct {
+ FirstName string `json:"first_name" xml:"first_name"`
+ LastName string `json:"last_name" xml:"last_name"`
+}
+
+func (author Author) String() string {
+ return author.FirstName + " " + author.LastName
+}
+
+type Book struct {
+ XMLName xml.Name `xml:"book"`
+ ISBN string `xml:"isbn,attr"`
+ Title string
+ Author Author
+}
+
+func (book Book) String() string {
+ return fmt.Sprintf("[%s] %s от %s", book.ISBN, book.Title, book.Author)
+}
+
+type LibraryResponse interface {
+ GetBook() (fmt.Stringer, error)
+ GetAvailability() (available int, registered int)
+}
+
+type Response struct {
+ book Book
+ availability int
+ registered int
+ err error
+}
+
+func (response Response) GetBook() (fmt.Stringer, error) {
+ if response.err == nil {
+ return response.book, nil
+ } else {
+ return nil, response.err
+ }
+}
+
+func (response Response) GetAvailability() (available int, registered int) {
+ return response.availability, response.registered
+}
+
+type LibraryRequest interface {
+ GetType() int
+ GetISBN() string
+}
+
+type Librarian struct {
+ request chan LibraryRequest
+ response chan LibraryResponse
+ store LibraryStore
+}
+
+type Library interface {
+ AddBookJSON(data []byte) (int, error)
+ AddBookXML(data []byte) (int, error)
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryStore struct {
+ librarians chan Librarian
+ books map[string][]Book
+ available map[string]int
+ lock sync.Mutex
+}
+
+func (store LibraryStore) addBook(book Book) (int, error) {
+ if _, ok := store.books[book.ISBN]; !ok {
+ store.books[book.ISBN] = []Book{}
+ store.available[book.ISBN] = 0
+ }
+
+ booksCount := len(store.books[book.ISBN])
+ if booksCount < 4 {
+ store.books[book.ISBN] = append(store.books[book.ISBN], book)
+ store.available[book.ISBN] += 1
+ return booksCount + 1, nil
+ } else {
+ return booksCount, errors.New("Има 4 копия на книга " + book.ISBN)
+ }
+
+}
+
+func (store LibraryStore) AddBookJSON(data []byte) (int, error) {
+ var book Book
+ err := json.Unmarshal(data, &book)
+
+ if err != nil {
+ return 0, err
+ }
+
+ store.lock.Lock()
+ defer store.lock.Unlock()
+
+ return store.addBook(book)
+}
+
+func (store LibraryStore) AddBookXML(data []byte) (int, error) {
+ var book Book
+ err := xml.Unmarshal(data, &book)
+
+ if err != nil {
+ return 0, err
+ }
+
+ store.lock.Lock()
+ defer store.lock.Unlock()
+
+ return store.addBook(book)
+}
+
+func handleBorrow(store LibraryStore, request LibraryRequest) Response {
+ books, ok := store.books[request.GetISBN()]
+ availability := store.available[request.GetISBN()]
+ var response Response
+
+ if !ok {
+ response = Response{err: errors.New("Непозната книга " + request.GetISBN())}
+ } else if availability == 0 {
+ response = Response{
+ registered: len(books),
+ err: errors.New("Няма наличност на книга " + request.GetISBN())}
+ } else {
+ availability -= 1
+ store.available[request.GetISBN()] = availability
+
+ response = Response{
+ availability: availability,
+ registered: len(books),
+ book: books[0],
+ }
+ }
+
+ return response
+}
+
+func handleReturn(store LibraryStore, request LibraryRequest) Response {
+ books, ok := store.books[request.GetISBN()]
+ availability := store.available[request.GetISBN()]
+ var response Response
+
+ if !ok {
+ response = Response{err: errors.New("Непозната книга " + request.GetISBN())}
+ } else if availability == len(books) {
+ response = Response{
+ err: errors.New("Всички копия са налични " + request.GetISBN()),
+ registered: len(books),
+ availability: availability,
+ }
+ } else {
+ availability += 1
+ store.available[request.GetISBN()] = availability
+
+ response = Response{
+ availability: availability,
+ registered: len(books),
+ book: books[0],
+ }
+ }
+
+ return response
+}
+
+func handleAvailability(store LibraryStore, request LibraryRequest) Response {
+ books, ok := store.books[request.GetISBN()]
+ availability := store.available[request.GetISBN()]
+ var response Response
+
+ if !ok {
+ response = Response{err: errors.New("Непозната книга " + request.GetISBN())}
+ } else {
+ store.available[request.GetISBN()] = availability
+
+ response = Response{
+ availability: availability,
+ registered: len(books),
+ book: books[0],
+ }
+ }
+
+ return response
+}
+
+func (store LibraryStore) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ librarian := <-store.librarians
+ librarian.request = make(chan LibraryRequest)
+ librarian.response = make(chan LibraryResponse)
+
+ go func() {
+ for request := range librarian.request {
+ store := librarian.store
+ store.lock.Lock()
+ var response Response
+
+ switch request.GetType() {
+ case 1:
+ response = handleBorrow(store, request)
+ case 2:
+ response = handleReturn(store, request)
+ case 3:
+ response = handleAvailability(store, request)
+ }
+
+ librarian.response <- response
+
+ store.lock.Unlock()
+ }
+ store.librarians <- Librarian{}
+ }()
+
+ return librarian.request, librarian.response
+}
+
+func NewLibrary(librariansCount int) Library {
+ store := LibraryStore{
+ books: make(map[string][]Book),
+ available: make(map[string]int),
+ }
+
+ librarians := make(chan Librarian, librariansCount)
+ for i := 0; i < librariansCount; i++ {
+ librarians <- Librarian{store: store}
+ }
+
+ store.librarians = librarians
+ return store
+}