Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ option(ENABLE_TESTING "Build small (unit) tests" ON)

# ================ Project ========================
# Project name and a few useful settings
project(ip_filter
project(allocator
VERSION 0.0.$ENV{TRAVIS_BUILD_NUMBER}
DESCRIPTION "OTUS c++ homeworks: ip_filter"
DESCRIPTION "OTUS c++ homeworks: allocator"
LANGUAGES CXX
)

Expand Down
4 changes: 4 additions & 0 deletions apps/Allocator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
add_and_install_project_app(allocator
DEPEND
lib_Allocator
)
56 changes: 56 additions & 0 deletions apps/Allocator/src/main_Allocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include <Allocator/Allocator.h>
#include <Allocator/List.h>

#include <iostream>
#include <map>


int main() {
size_t factorial = 1;

// map with std::allocator
std::map<int, int> std_m;
for (size_t i = 0; i < 10; ++i) {
std_m[i] = factorial;
factorial *= (i+1);
}
for (auto it = std_m.begin(); it != std_m.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}

// map with custom allocator
factorial = 1;
std::map<int, int, std::less<int>,
Allocator::Allocator<std::pair<const int, int>, 10>> m;
for (size_t i = 0; i < 10; ++i) {
m[i] = factorial;
factorial *= (i+1);
}
for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}

// custom container with std::allocator
Allocator::List<int> std_l;
for (int i = 0; i < 10; ++i) {
std_l.push_back(i);
}
for (auto it = std_l.begin(); it != std_l.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

// custom container with custom allocator
Allocator::List<int, Allocator::Allocator<int, 11>> l;
for (int i = 0; i < 10; ++i) {
l.push_back(i);
}
for (auto it = l.begin(); it != l.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;



return 0;
}
3 changes: 2 additions & 1 deletion apps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# add_subdirectory(HelloWorld)
add_subdirectory(IpFilter)
# add_subdirectory(IpFilter)
add_subdirectory(Allocator)
2 changes: 1 addition & 1 deletion apps/HelloWorld/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
add_and_install_project_app(helloworld
DEPEND
HelloWorld
lib_HelloWorld
)
2 changes: 1 addition & 1 deletion apps/IpFilter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
add_and_install_project_app(ip_filter
DEPEND
IpFilter
lib_IpFilter
)
7 changes: 4 additions & 3 deletions cmake/project_target.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
function(add_project_library)
get_filename_component(lib_name "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
set(lib_name lib${lib_name})
set(lib_name lib_${lib_name})

glob_target_files(${lib_name}
TARGET_ROOT ${CMAKE_CURRENT_SOURCE_DIR})

Expand Down Expand Up @@ -50,7 +51,7 @@ function(add_project_test)
)

target_link_libraries(${test_name}
lib${target_name}
lib_${target_name}
${Boost_LIBRARIES}
)

Expand Down Expand Up @@ -78,7 +79,7 @@ function(add_and_install_project_app app_name)

set(app_lib_dependency "")
foreach(link_lib ${add_project_app_DEPEND})
LIST(APPEND app_lib_dependency lib${link_lib})
LIST(APPEND app_lib_dependency ${link_lib})
endforeach()

target_link_libraries(${app_name}
Expand Down
3 changes: 3 additions & 0 deletions library/Allocator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_project_library()

add_subdirectory(test)
138 changes: 138 additions & 0 deletions library/Allocator/include/Allocator/Allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#pragma once

#include <cstdlib>
#include <new>
#include <utility>
#include <algorithm>

namespace Allocator {

//--------------------------------------
#pragma mark Allocator declaration
//--------------------------------------

template<typename T, size_t N>
class Allocator{
public:
using value_type = T;
using pointer = T*;
Allocator();

template<typename U>
struct rebind;

pointer allocate(std::size_t n = 1);
void deallocate(pointer p, std::size_t n);
template<typename U, typename ...Args>
void construct(U *p, Args&&... args);
void destroy(pointer p);

~Allocator();

bool operator==(const Allocator& other);
bool operator!=(const Allocator& other);

private:
T* FindAvailableChunk(std::size_t n);

const size_t max_allocatable_objects;
bool *m_free_chunks = nullptr;
T *m_area = nullptr;
};

//--------------------------------------
#pragma mark Implementation
//--------------------------------------

template<typename T, size_t N>
Allocator<T, N>::Allocator(): max_allocatable_objects(N) {}

template<typename T, size_t N>
template<typename U>
struct Allocator<T, N>::rebind{
using other = Allocator<U, N>;
};

template<typename T, size_t N>
T* Allocator<T, N>::allocate(std::size_t n) {
if (nullptr == m_area) {
m_area = static_cast<T*> (::operator new (max_allocatable_objects*sizeof(T)));
if (nullptr == m_area) {
throw std::bad_alloc();
}
m_free_chunks = new bool[max_allocatable_objects];
if (m_free_chunks == nullptr) {
throw std::bad_alloc();
}
std::fill_n(m_free_chunks, max_allocatable_objects, true);
}
if (n > max_allocatable_objects)
throw std::bad_alloc{};
auto p = FindAvailableChunk(n);
return p;
}

template<typename T, size_t N>
void Allocator<T, N>::deallocate(T *p, std::size_t n) {
int pos = (p-m_area);
if (pos < 0 || pos + n > max_allocatable_objects)
throw std::bad_alloc{};
while (n >0) {
m_free_chunks[pos] = false;
++pos;
--n;
}
}

template<typename T, size_t N>
template<typename U, typename ...Args>
void Allocator<T, N>::construct(U *p, Args&&... args) {
new(p) U(std::forward<Args>(args)...);
}

template<typename T, size_t N>
void Allocator<T, N>::destroy(T *p) {
p->~T();
}

template<typename T, size_t N>
Allocator<T, N>::~Allocator() {
::operator delete(m_area);
delete [] m_free_chunks;
}

template<typename T, size_t N>
bool Allocator<T, N>::operator==(const Allocator& other) {
return true;
}

template<typename T, size_t N>
bool Allocator<T, N>::operator!=(const Allocator& other) {
return !((*this)==other);
}

template<typename T, size_t N>
T* Allocator<T, N>::FindAvailableChunk(std::size_t n) {
size_t idx = 0;
bool stop = false;
while (!stop && idx + n < max_allocatable_objects) {
while (!m_free_chunks[idx] && idx + n < max_allocatable_objects) {
++idx;
}
bool s = true;
for (int i = 0; i < n; ++i) {
s &= m_free_chunks[idx+i];
}
stop |= s;
}
if (idx+n > max_allocatable_objects)
throw std::bad_alloc{};
else{
for (int i = 0; i < n; ++i){
m_free_chunks[idx+i] = false;
}
return m_area + idx;
}
}

} // namespace Allocator
88 changes: 88 additions & 0 deletions library/Allocator/include/Allocator/List.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#pragma once

#include <memory>

namespace Allocator {

//------------------------------------------------------------
#pragma mark List Declaration
//------------------------------------------------------------

template <typename T, typename Allocator = std::allocator<T>>
class List
{
public:
using value_type = typename std::allocator_traits<Allocator>::value_type;
private:
struct Node {
value_type data = value_type();
Node *next = nullptr;
};

using NodeAllocator = typename Allocator::template rebind<Node>::other;

public:
struct iterator
{
Node* m_ptr;

iterator(Node* ptr) : m_ptr(ptr) {}

iterator operator++() {
m_ptr = m_ptr->next;

return *this; }
T& operator*() { return m_ptr->data; }
bool operator==(const iterator& rhs) { return m_ptr == rhs.m_ptr; }
bool operator!=(const iterator& rhs) { return m_ptr != rhs.m_ptr; }
};

List();

auto begin() -> iterator { return iterator(m_dummy_head->next); }
auto end() -> iterator { return iterator(m_tail->next); }
auto begin() const -> const iterator { return iterator(m_dummy_head->next); }
auto end() const -> const iterator { return iterator(m_tail->next); }
void push_back(const value_type &t);
~List();

private:
Node *m_dummy_head = nullptr, *m_tail = nullptr;
NodeAllocator m_node_allocator;
};

//------------------------------------------------------------
#pragma mark List Implementation
//------------------------------------------------------------

template <typename T, typename Allocator>
List<T, Allocator>::List(): m_dummy_head() {
m_dummy_head = m_node_allocator.allocate(1);
m_node_allocator.construct(m_dummy_head, Node{});
m_tail = m_dummy_head;
}

template <typename T, typename Allocator>
void List<T, Allocator>::push_back(const value_type &t) {
Node *node = m_node_allocator.allocate(1);
m_node_allocator.construct(node, Node{t, nullptr});
m_tail->next = node;
m_tail = node;
}

template <typename T, typename Allocator>
List<T, Allocator>::~List()
{
auto node = m_dummy_head->next;
while (node != nullptr)
{
auto next_node = node->next;
m_node_allocator.deallocate(node, 1);
m_node_allocator.destroy(node);
node = next_node;
}
m_node_allocator.deallocate(m_dummy_head, 1);
m_node_allocator.destroy(m_dummy_head);
}

} // namespace slist
1 change: 1 addition & 0 deletions library/Allocator/src/Allocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include <Allocator/Allocator.h>
1 change: 1 addition & 0 deletions library/Allocator/src/List.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include <Allocator/List.h>
1 change: 1 addition & 0 deletions library/Allocator/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_project_test()
Loading