Входной файл: | Стандартный вход | Ограничение времени: | 25 сек | |
Выходной файл: | Стандартный выход | Ограничение памяти: | 512 Мб |
Вам необходимо реализовать класс SmartPointer
, интерфейс которого находится в файле SmartPointer.hpp
,
а также реализовать вспомогательный класс Core
.
При реализации класса SmartPointer
нельзя добавлять новые поля.
Входной файл: | Стандартный вход | Ограничение времени: | 1 сек | |
Выходной файл: | Стандартный выход | Ограничение памяти: | 4096 Мб |
Реализуйте паттерн проектирования "Фабрика".
Фабрика может создавать произвольных потомков базового класса. В нашем случае
базовым классом будет Object
, а сама фабрика — классом Factory
.
Определение класса Object
должно быть в точности таким:
class Object {
public:
virtual std::string ToString() const = 0;
virtual ~Object() {}
};
Метод ToString
является абстрактным. Это означает, что все потомки
Object
обязаны перегрузить этот метод.
Ваша фабрика должна уметь понимать, потомка какого типа от неё хотят получить в данный момент. Это означает, что у каждого потомка должен быть некоторый идентификатор. В этом задании будем использовать строковые идентификаторы.
Фабрика поддерживает всего две операции. Одна из них:
Object* Create(const std::string& class_id)
— этот метод
класса Factory
получает на вход идентификатор класса, создает экземпляр этого класса
и возвращает указатель на созданный экземпляр.
Сразу после конструирования ваша фабрика должна уметь создавать потомков с
идентификаторами "apple!", "list" и "yet another identifier". В этом задании
все потомки Object
при вызове ToString
должны
возвращать свои идентификаторы.
Например, код
Factory factory;
Object* apple_instance_ptr = factory.Create("apple!");
cout << apple_instance_ptr->ToString() << endl;
должен печатать "apple!".
Чтобы не было скучно, ваша фабрика должна поддерживать создание любых потомков
Object
. Для этого существует операция регистрации:
void Register(const std::string& class_id, Object*(*instance_creator)())
—
этот метод связывает идентификатор класса class_id
с порождающей функцией instance_creator
.
Параметр instance_creator
— это указатель на функцию, которая
возвращает указатель на наследника Object
.
Пример использования:
Factory factory;
factory.Register("smth", new_smth);
Object* smth_instance_ptr = factory.Create("smth");
cout << smth_instance_ptr->ToString() << endl;
Где new_smth
это функция, объявленная как Object* new_smth();
Файл с решением должен содержать только реализацию классов Factory и Object и вспомогательных классов, если необходимы.
Входной файл: | Стандартный вход | Ограничение времени: | 2 сек | |
Выходной файл: | Стандартный выход | Ограничение памяти: | 128 Мб |
Конструктор класса PageAllocator
принимает размер блока в байтах
Функция Allocate
выделяет блок размера, заданного в конструкторе
Данный класс реализовывать не нужно
class PageAllocator {
public:
explicit PageAllocator(std::uint64_t page_size);
void* Allocate();
};
Необходимо реализовать класс FixedAllocator
, у которого должны быть:
Конструктор принимающий page_size
— размер блока в элементах типа Tp
Функция Allocate
возвращающая указатель на следующую свободную память
Если свободной памяти нет функция Allocate
получает ее через объект page_allocator_
Функция Deallocate
добавляющая указатель обратно в пул свободной памяти
Функция InnerAllocator
возвращающая неизменяемую ссылку на объект page_allocator_
template<typename Tp>
class FixedAllocator {
PageAllocator page_allocator_;
public:
explicit FixedAllocator(std::uint64_t page_size);
Tp* Allocate();
void Deallocate(Tp* p);
const PageAllocator& InnerAllocator() const noexcept;
};
Таким образом вы должны выделять минимально возможное кол-во блоков памяти (кол-во вывозов Allocate
у объекта page_allocator_
)
Выделять память можно только с помощью данного объекта
Файл с решением должен содержать только реализацию класса FixedAllocator
Входной файл: | Стандартный вход | Ограничение времени: | 1 сек | |
Выходной файл: | Стандартный выход | Ограничение памяти: | 4000 Мб |
Вам заданны классы узлов синтаксического дерева программы, необходимые для описания объявления класса, методов класса и полей класса.
class ClassDeclarationNode;
class VarDeclarationNode;
class MethodDeclarationNode;
class BaseNode;
class BaseVisitor {
public:
virtual void Visit(const BaseNode* node) = 0;
virtual void Visit(const ClassDeclarationNode* node) = 0;
virtual void Visit(const VarDeclarationNode* node) = 0;
virtual void Visit(const MethodDeclarationNode* node) = 0;
};
class BaseNode {
public:
virtual void Visit(BaseVisitor* visitor) const = 0;
};
class ClassDeclarationNode: public BaseNode {
public:
const std::string& ClassName() const;
const std::vector<BaseNode*>& PublicFields() const;
const std::vector<BaseNode*>& ProtectedFields() const;
const std::vector<BaseNode*>& PrivateFields() const;
void Visit(BaseVisitor* visitor) const override {
visitor->Visit(this);
}
};
class VarDeclarationNode: public BaseNode {
public:
const std::string& VarName() const;
const std::string& TypeName() const;
void Visit(BaseVisitor* visitor) const override {
visitor->Visit(this);
}
};
class MethodDeclarationNode: public BaseNode {
public:
const std::string& MethodName() const;
const std::string& ReturnTypeName() const;
const std::vector<BaseNode*>& Arguments() const;
void Visit(BaseVisitor* visitor) const override {
visitor->Visit(this);
}
};
Требуется реализовать класс FormatVisitor
, который будет позволять получать отформатированное представление программы в виде строки,
в соответствии с синтаксисом языка C++
и Google Style Guide.
class FormatVisitor: public BaseVisitor {
public:
void Visit(const BaseNode* node) override {
node->Visit(this);
}
void Visit(const ClassDeclarationNode* node) override;
void Visit(const VarDeclarationNode* node) override;
void Visit(const MethodDeclarationNode* node) override;
const std::vector<std::string>& GetFormattedCode() const;
};
Файл с решением должен содержать только реализацию описанного класса, без функции main.
Входной файл: | Стандартный вход | Ограничение времени: | 1 сек | |
Выходной файл: | Стандартный выход | Ограничение памяти: | 4000 Мб |
Необходимо реализовать класс GameDatabase
cо следующим интерфейсом:
class GameDatabase
{
public:
GameDatabase() = default;
/// вставляет в базу объект с именем [name] и позицией [x, y]
/// если объект с таким id в базе уже есть, заменяет его новым
void Insert(ObjectId id, string name, size_t x, size_t y)
/// удаляет элемент по id
/// если такого элемента нет, ничего не делает
void Remove(ObjectId id);
/// возвращает вектор объектов c именем [name]
/// сортировка по убыванию id
vector<GameObject> DataByName(string name) const;
/// возвращает вектор объектов, находящихся в позиции [x, y]
/// сортировка по убыванию id
vector<GameObject> DataByPosition(size_t x, size_t y) const;
/// возвращает вектор всех объектов из базы
/// сортировка по убыванию id
vector<GameObject> Data() const;
};
Код для GameObject
и ObjectId
указан ниже.
using ObjectId = unsigned long long int;
struct GameObject
{
ObjectId id;
string name;
size_t x;
size_t y;
};
Рекомендуется использовать структуры данных: std::unordered_map
, std::map
, std::set
Отдельная сортировка не потребуется если использовать компаратор для упорядоченных контейнеров (std::set
, std::map
)
Пример организации данных с компаратором:
bool operator>(const GameObject& a, const GameObject& b) {
return a.id > b.id;
}
template<class Tp, template<class> class Compare>
class DereferenceCompare {
Compare<Tp> comp;
public:
bool operator()(const Tp* const a, const Tp* const b) const {
return comp(*a, *b);
}
};
/// быстрый доступ по id
std::map<ObjectId, GameObject, std::greater<ObjectId>>
/// быстрый доступ по позиции
std::map<std::pair<size_t, size_t>, std::set<GameObject*, DereferenceCompare<GameObject, std::greater>>>
/// быстрый доступ по имени
std::unordered_map<string, std::set<GameObject*, DereferenceCompare<GameObject, std::greater>>>
Файл с решением должен содержать только реализацию класса GameDatabase
без функции main
.