Решение на Concurrent Tasks от Добромир Иванов

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

Към профила на Добромир Иванов

Резултати

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

Код

package main
import (
"encoding/json"
"encoding/xml"
"fmt"
"sync"
)
type Library interface {
AddBookJSON(data []byte) (int, error)
AddBookXML(data []byte) (int, error)
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryRequest interface {
GetType() int
GetISBN() string
}
type LibraryResponse interface {
GetBook() (fmt.Stringer, error)
GetAvailability() (available int, registered int)
}
type Author struct {
FirstName string `xml:"first_name" json:"first_name"`
LastName string `xml:"last_name" json:"last_name"`
}
type Book struct {
Isbn string `xml:"isbn,attr"`
Title string `xml:"title"`
Ratings []int `xml:"ratings>rating"`
BookAuthor Author `xml:"author" json:"author"`
available bool
}
type SimpleLibrary struct {
Books map[string][]*Book
Librarians chan struct{}
sync.RWMutex
}
type SimpleLibraryResponse struct {
book Book
err error
available int
registered int
}
type LibraryError struct {
ErrorMessage string
}
func (book Book) String() string {
return fmt.Sprintf("[%s] %s от %s %s", book.Isbn, book.Title,
book.BookAuthor.FirstName, book.BookAuthor.LastName)
}
func (response SimpleLibraryResponse) GetBook() (fmt.Stringer, error) {
if response.book.Isbn == "" {
return nil, response.err
}
return response.book, response.err
}
func (response SimpleLibraryResponse) GetAvailability() (int, int) {
return response.available, response.registered
}
func (libraryError LibraryError) Error() string {
return libraryError.ErrorMessage
}
func NewLibrary(librarians int) SimpleLibrary {
librarianChan := make(chan struct{}, librarians)
for i := 0; i < librarians; i++ {
librarianChan <- struct{}{}
}
return SimpleLibrary{Books: make(map[string][]*Book),
Librarians: librarianChan}
}
func (library SimpleLibrary) AddBookJSON(data []byte) (int, error) {
var book Book
err := json.Unmarshal(data, &book)
if err != nil {
return len(library.Books), err
}
return library.addBook(&book)
}
func (library SimpleLibrary) AddBookXML(data []byte) (int, error) {
var book Book
err := xml.Unmarshal([]byte(data), &book)
if err != nil {
return len(library.Books), err
}
return library.addBook(&book)
}
func (library SimpleLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
requestChan := make(chan LibraryRequest)
responseChan := make(chan LibraryResponse)
<-library.Librarians
go func(requestChan <-chan LibraryRequest, responseChan chan<- LibraryResponse) {
for request := range requestChan {
switch request.GetType() {
case 1:
responseChan <- library.borrowBook(request.GetISBN())
case 2:
responseChan <- library.returnBook(request.GetISBN())
case 3:
responseChan <- library.checkBook(request.GetISBN())
}
}
library.Librarians <- struct{}{}
}(requestChan, responseChan)
return requestChan, responseChan
}
func (library SimpleLibrary) getAvailability(isbn string) int {
_, ok := library.Books[isbn]
availability := 0
if !ok {
return availability
}
for _, book := range library.Books[isbn] {
if book.available {
availability++
}
}
return availability
}
func (library SimpleLibrary) addBook(book *Book) (int, error) {
library.Lock()
defer library.Unlock()
_, ok := library.Books[book.Isbn]
if !ok {
library.Books[book.Isbn] = make([]*Book, 0, 4)
}
if len(library.Books[book.Isbn]) < 4 {
book.available = true
library.Books[book.Isbn] = append(library.Books[book.Isbn], book)
} else {
err := LibraryError{fmt.Sprintf("Има 4 копия на книга %s", book.Isbn)}
return len(library.Books[book.Isbn]), err
}
return len(library.Books[book.Isbn]), nil
}
func (library SimpleLibrary) borrowBook(isbn string) SimpleLibraryResponse {
library.Lock()
defer library.Unlock()
_, ok := library.Books[isbn]
if !ok {
err := LibraryError{fmt.Sprintf("Непозната книга %s", isbn)}
response := SimpleLibraryResponse{book: Book{}, err: err,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
return response
}
for _, book := range library.Books[isbn] {
if book.available {
book.available = false
response := SimpleLibraryResponse{book: *book, err: nil,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
return response
}
}
err := LibraryError{fmt.Sprintf("Няма наличност на книга %s", isbn)}
response := SimpleLibraryResponse{book: Book{}, err: err,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
return response
}
func (library SimpleLibrary) returnBook(isbn string) SimpleLibraryResponse {
library.Lock()
defer library.Unlock()
_, ok := library.Books[isbn]
if !ok {
err := LibraryError{fmt.Sprintf("Непозната книга %s", isbn)}
response := SimpleLibraryResponse{book: Book{}, err: err,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
return response
}
for _, book := range library.Books[isbn] {
if !book.available {
book.available = true
response := SimpleLibraryResponse{book: *book, err: nil,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
return response
}
}
err := LibraryError{fmt.Sprintf("Всички копия са налични %s", isbn)}
return SimpleLibraryResponse{book: Book{}, err: err,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
}
func (library SimpleLibrary) checkBook(isbn string) SimpleLibraryResponse {
library.RLock()
defer library.RUnlock()
_, ok := library.Books[isbn]
if !ok {
err := LibraryError{fmt.Sprintf("Непозната книга %s", isbn)}
response := SimpleLibraryResponse{book: Book{}, err: err,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
return response
}
return SimpleLibraryResponse{book: *library.Books[isbn][0], err: nil,
available: library.getAvailability(isbn),
registered: len(library.Books[isbn])}
}

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

PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.003s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.004s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.004s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.004s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.003s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.003s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.004s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.004s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.004s
PASS
ok  	_/tmp/d20151207-5667-bzfbs5	0.003s

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

Добромир обнови решението на 06.12.2015 17:07 (преди над 2 години)

+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "sync"
+)
+
+type Library interface {
+ AddBookJSON(data []byte) (int, error)
+ AddBookXML(data []byte) (int, error)
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+ GetType() int
+ GetISBN() string
+}
+
+type LibraryResponse interface {
+ GetBook() (fmt.Stringer, error)
+ GetAvailability() (available int, registered int)
+}
+
+type Author struct {
+ FirstName string `xml:"first_name" json:"first_name"`
+ LastName string `xml:"last_name" json:"last_name"`
+}
+
+type Book struct {
+ Isbn string `xml:"isbn,attr"`
+ Title string `xml:"title"`
+ Ratings []int `xml:"ratings>rating"`
+ BookAuthor Author `xml:"author" json:"author"`
+ available bool
+}
+
+type SimpleLibrary struct {
+ Books map[string][]*Book
+ Librarians chan struct{}
+ sync.RWMutex
+}
+
+type SimpleLibraryResponse struct {
+ book Book
+ err error
+ available int
+ registered int
+}
+
+type LibraryError struct {
+ ErrorMessage string
+}
+
+func (book Book) String() string {
+ return fmt.Sprintf("[%s] %s от %s %s", book.Isbn, book.Title,
+ book.BookAuthor.FirstName, book.BookAuthor.LastName)
+}
+
+func (response SimpleLibraryResponse) GetBook() (fmt.Stringer, error) {
+ if response.book.Isbn == "" {
+ return nil, response.err
+ }
+ return response.book, response.err
+}
+
+func (response SimpleLibraryResponse) GetAvailability() (int, int) {
+ return response.available, response.registered
+}
+
+func (libraryError LibraryError) Error() string {
+ return libraryError.ErrorMessage
+}
+
+func NewLibrary(librarians int) SimpleLibrary {
+ librarianChan := make(chan struct{}, librarians)
+ for i := 0; i < librarians; i++ {
+ librarianChan <- struct{}{}
+ }
+
+ return SimpleLibrary{Books: make(map[string][]*Book),
+ Librarians: librarianChan}
+}
+
+func (library SimpleLibrary) AddBookJSON(data []byte) (int, error) {
+ var book Book
+
+ err := json.Unmarshal(data, &book)
+ if err != nil {
+ return len(library.Books), err
+ }
+
+ return library.addBook(&book)
+}
+
+func (library SimpleLibrary) AddBookXML(data []byte) (int, error) {
+ var book Book
+
+ err := xml.Unmarshal([]byte(data), &book)
+ if err != nil {
+ return len(library.Books), err
+ }
+
+ return library.addBook(&book)
+}
+
+func (library SimpleLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ requestChan := make(chan LibraryRequest)
+ responseChan := make(chan LibraryResponse)
+ <-library.Librarians
+ go func(requestChan <-chan LibraryRequest, responseChan chan<- LibraryResponse) {
+ for request := range requestChan {
+ switch request.GetType() {
+ case 1:
+ responseChan <- library.borrowBook(request.GetISBN())
+ case 2:
+ responseChan <- library.returnBook(request.GetISBN())
+ case 3:
+ responseChan <- library.checkBook(request.GetISBN())
+ }
+ }
+ library.Librarians <- struct{}{}
+ }(requestChan, responseChan)
+ return requestChan, responseChan
+}
+
+func (library SimpleLibrary) getAvailability(isbn string) int {
+ _, ok := library.Books[isbn]
+ availability := 0
+
+ if !ok {
+ return availability
+ }
+
+ for _, book := range library.Books[isbn] {
+ if book.available {
+ availability++
+ }
+ }
+
+ return availability
+}
+
+func (library SimpleLibrary) addBook(book *Book) (int, error) {
+ library.Lock()
+ defer library.Unlock()
+
+ _, ok := library.Books[book.Isbn]
+ if !ok {
+ library.Books[book.Isbn] = make([]*Book, 0, 4)
+ }
+
+ if len(library.Books[book.Isbn]) < 4 {
+ book.available = true
+ library.Books[book.Isbn] = append(library.Books[book.Isbn], book)
+ } else {
+ err := LibraryError{fmt.Sprintf("Има 4 копия на книга %s", book.Isbn)}
+ return len(library.Books[book.Isbn]), err
+ }
+
+ return len(library.Books[book.Isbn]), nil
+}
+
+func (library SimpleLibrary) borrowBook(isbn string) SimpleLibraryResponse {
+ library.Lock()
+ defer library.Unlock()
+
+ _, ok := library.Books[isbn]
+ if !ok {
+ err := LibraryError{fmt.Sprintf("Непозната книга %s", isbn)}
+ response := SimpleLibraryResponse{book: Book{}, err: err,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+ return response
+ }
+
+ for _, book := range library.Books[isbn] {
+ if book.available {
+ book.available = false
+
+ response := SimpleLibraryResponse{book: *book, err: nil,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+ return response
+ }
+ }
+
+ err := LibraryError{fmt.Sprintf("Няма наличност на книга %s", isbn)}
+ response := SimpleLibraryResponse{book: Book{}, err: err,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+ return response
+}
+
+func (library SimpleLibrary) returnBook(isbn string) SimpleLibraryResponse {
+ library.Lock()
+ defer library.Unlock()
+
+ _, ok := library.Books[isbn]
+ if !ok {
+ err := LibraryError{fmt.Sprintf("Непозната книга %s", isbn)}
+ response := SimpleLibraryResponse{book: Book{}, err: err,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+ return response
+ }
+
+ for _, book := range library.Books[isbn] {
+ if !book.available {
+ book.available = true
+ response := SimpleLibraryResponse{book: *book, err: nil,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+
+ return response
+ }
+ }
+
+ err := LibraryError{fmt.Sprintf("Всички копия са налични %s", isbn)}
+ return SimpleLibraryResponse{book: Book{}, err: err,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+}
+
+func (library SimpleLibrary) checkBook(isbn string) SimpleLibraryResponse {
+ library.RLock()
+ defer library.RUnlock()
+
+ _, ok := library.Books[isbn]
+ if !ok {
+ err := LibraryError{fmt.Sprintf("Непозната книга %s", isbn)}
+ response := SimpleLibraryResponse{book: Book{}, err: err,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+ return response
+ }
+
+ return SimpleLibraryResponse{book: *library.Books[isbn][0], err: nil,
+ available: library.getAvailability(isbn),
+ registered: len(library.Books[isbn])}
+}