<commit_before># Request Buffer

Често се налага да се правят време-отнемащи задачи които ще наречем заявки. Резултата от тези задачи често може да бъде запазен и използван вместо отново да се изпълняват същите задачи. Това се нарича кеширанe. В допълнение е възможно докато се изпълнява задача да се получат заявки за същата задача, преди първата такава да е приключила. В такъв случай искаме само първата наистина да се 'извърши', а останалите да изчакат и използват резултата ѝ на готово.

Имайки следния интерфейс, описващ една заявка:

```go
type Request interface{
	// Връща идентификатор за заявката. Ако две заявки имат еднакви идентификатори
	// то те са "равни".
	ID() string

	// Блокира докато изпълнява заявката.
	// Връща резултата или грешка ако изпълнението е неуспешно.
	// Резултата и грешката не трябва да бъдат подавани на SetResult
	// за текущата заявка - те са запазват вътрешно преди да бъдат върнати.
	Run() (result interface{}, err error)

	// Връща дали заявката е кешируерма.
	// Метода има неопределено поведение ако бъде извикан преди `Run`.
	Cacheable() bool

	// Задава резултата на заявката.
	// Не трябва да се извиква за заявки, за които е бил извикан `Run`.
	SetResult(result interface{}, err error)
}
```


Вашата задача е да имплементирате следния интерфейс:

```go
type Requester interface{
	// Добавя заявка за изпълнение и я изпълнява, ако това е необходимо, при първа възможност.
	AddRequest(request Request)

	// Спира 'Заявчика'. Това означава че изчаква всички вече започнали заявки да завършат
	// и извиква `SetResult` на тези заявки които вече са били добавени, но "равни" на тях вече са били изпълнявание.
	// Нови заявки не трябва да бъдат започвани през това време, нито ако вече започнати равни на тях да бъдат добавяни за извиквани на `SetResult`.
	Stop()
}
```

Както и функция(конструктор):

```go
// Връща нов заявчик, която кешира отговорите на до cacheSize заявки,
// изпълнявайке не повече от throttleSize заявки едновременно.
func NewRequester(cacheSize int, throttleSize int) Requester
```

Уточнения: 

1. Алгоритъмът за работа с вече запълнен кеш е "заместване на най-стария резултат", познат още като [цикличен буфер](https://en.wikipedia.org/wiki/Circular_buffer). Всякакви други алгоритми не сe приемат.
2. Ако се получи втора заявка, която да е същата като текущо обработваната се очаква че:
	1. Ще се изчака текущо изпълняващата се за да се види дали не е кешируема.
	2. Ако не е кешируема то заявката трябва да бъде изпълнена все едно не е имало такава със същото ID.
3. Aко `Cacheable` върне `true`, то това означава че тази заявка може да бъде кеширана. Отговора ѝ може да бъде използван от всички други "равни" на нея.
4. Ако `Cacheable` върне `false`, то това означава че заявката не може да бъде кеширана. Ако докато се е изпълнявала са дошли още 5 заявки със същото ID - то те трябва да я изчакат да видят дали няма да e кешируема.
5. `Run` или `SetRequest` приключва дадена заявка. Викането на единия и след това другия метод както и много кратното извикване на един от тях за една съща заявка има неопределено поведение - не го правете.


**ВАЖНО:** интерфейсите Requester и Request ще трябва да бъдат копирани в кода на решението ви. При извикването на тестовете в директорията трябва да има два файла `solution_test.go` с тестовете и вашото решение `solution.go` в което двата интерфейса са копирани.

Пример 1:

```go
	var req1, req2, req3 Request
	// инициализиране на req1, req2, req3 да са 3 "равни" Request-а, за които Cacheable връща true.
	requester := NewRequester(1, 1)
	requester.AddRequest(req1)
	go func() {
		requester.AddRequest(req2) // (1)
		requester.AddRequest(req3) // (2)
	}
	requester.Stop() // (3)
```
	1. req1 бива изпъленен чрез извикване на Run
	2. Ако (3) се изпълни преди (1): req2 и req3 не биват изпълнявани - нито `Run` нито `SetResult` биват извиквани за тях.
	3. Ако (3) се изпълни след (1) (и (2)): то за req2 (и req3) трябва да бъде извикан само `SetResult`<commit_msg>Fix some typos in the task description.<commit_after># Request Buffer

Често се налага да се правят време-отнемащи задачи, които ще наречем заявки. Резултата от тези задачи често може да бъде запазен и използван вместо отново да се изпълняват същите задачи. Това се нарича кеширанe. В допълнение е възможно докато се изпълнява задача да се получат заявки за същата задача, преди първата такава да е приключила. В такъв случай искаме само първата наистина да се 'извърши', а останалите да изчакат и използват резултата ѝ наготово.

Имайки следния интерфейс, описващ една заявка:

```go
type Request interface{
	// Връща идентификатор за заявката. Ако две заявки имат еднакви идентификатори
	// то те са "равни".
	ID() string

	// Блокира докато изпълнява заявката.
	// Връща резултата или грешка ако изпълнението е неуспешно.
	// Резултата и грешката не трябва да бъдат подавани на SetResult
	// за текущата заявка - те се запазват вътрешно преди да бъдат върнати.
	Run() (result interface{}, err error)

	// Връща дали заявката е кешируерма.
	// Метода има неопределено поведение, ако бъде извикан преди `Run`.
	Cacheable() bool

	// Задава резултата на заявката.
	// Не трябва да се извиква за заявки, за които е бил извикан `Run`.
	SetResult(result interface{}, err error)
}
```


Вашата задача е да имплементирате следния интерфейс:

```go
type Requester interface{
	// Добавя заявка за изпълнение и я изпълнява, ако това е необходимо, при първа възможност.
	AddRequest(request Request)

	// Спира 'Заявчика'. Това означава, че изчаква всички вече започнали заявки да завършат
	// и извиква `SetResult` на тези заявки, които вече са били добавени, но "равни" на тях вече са били изпълнявание.
	// Нови заявки не трябва да бъдат започвани през това време, нито вече започнати, равни на тях, да бъдат добавяни за извикване на `SetResult`.
	Stop()
}
```

Както и функция(конструктор):

```go
// Връща нов заявчик, който кешира отговорите на до cacheSize заявки,
// изпълнявайки не повече от throttleSize заявки едновременно.
func NewRequester(cacheSize int, throttleSize int) Requester
```

Уточнения:

1. Алгоритъмът за работа с вече запълнен кеш е "заместване на най-стария резултат", познат още като [цикличен буфер](https://en.wikipedia.org/wiki/Circular_buffer). Всякакви други алгоритми не сe приемат.
2. Ако се получи втора заявка, която да е същата като текущо обработваната, се очаква че:
	1. Ще се изчака текущо изпълняващата се, за да се види дали не е кешируема.
	2. Ако не е кешируема, то заявката трябва да бъде изпълнена все едно не е имало такава със същото ID.
3. Aко `Cacheable` върне `true`, то това означава, че тази заявка може да бъде кеширана. Отговора ѝ може да бъде използван от всички други "равни" на нея.
4. Ако `Cacheable` върне `false`, то това означава, че заявката не може да бъде кеширана. Ако докато се е изпълнявала са дошли още 5 заявки със същото ID - то те трябва да я изчакат, за да видят дали няма да e кешируема.
5. `Run` или `SetRequest` приключва дадена заявка. Викането на единия и след това другия метод, както и многократното извикване на един от тях за една съща заявка има неопределено поведение - не го правете.

**ВАЖНО:** интерфейсите Requester и Request ще трябва да бъдат копирани в кода на решението ви. При извикването на тестовете в директорията трябва да има два файла - `solution_test.go` с тестовете, и `solution.go` - с вашото решение, в което двата интерфейса са копирани.

Пример 1:

```go
	var req1, req2, req3 Request
	// инициализиране на req1, req2, req3 да са 3 "равни" Request-а, за които Cacheable връща true.
	requester := NewRequester(1, 1)
	requester.AddRequest(req1)
	go func() {
		requester.AddRequest(req2) // (1)
		requester.AddRequest(req3) // (2)
	}
	requester.Stop() // (3)
```
	1. req1 бива изпъленен чрез извикване на Run
	2. Ако (3) се изпълни преди (1): req2 и req3 не биват изпълнявани - нито `Run`, нито `SetResult` биват извиквани за тях.
	3. Ако (3) се изпълни след (1) (и (2)): то за req2 (и req3) трябва да бъде извикан само `SetResult`
{'fraction_non_alphanumeric': 0.07156238291494942, 'fraction_numerical': 0.00924191332583989, 'mean_word_length': 4.110402042118698, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1275196', 'n_tokens_mistral': 3409, 'n_tokens_neox': 3926, 'n_words': 1184}