blob: b37af3e53c5cbeaf205264dc1b43490c67cda5b1 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <cstddef>
#include <type_traits>
#include "vec/common/allocator.h"
#include "vec/common/allocator_fwd.h"
namespace doris {
#include "common/compile_check_begin.h"
template <class T, typename MemoryAllocator = Allocator<false>>
class CustomStdAllocator;
template <typename T>
using DorisVector = std::vector<T, CustomStdAllocator<T>>;
template <class Key, class T, class Compare = std::less<Key>,
class Allocator = CustomStdAllocator<std::pair<const Key, T>>>
using DorisMap = std::map<Key, T, Compare, Allocator>;
template <typename T>
requires(std::is_trivial_v<T> && std::is_standard_layout_v<T>)
struct DorisUniqueBufferDeleter : public Allocator<false> {
size_t count = 0;
DorisUniqueBufferDeleter() = default;
DorisUniqueBufferDeleter(size_t n) : count(n) {}
void operator()(T* ptr) const noexcept {
if (ptr) {
Allocator::free(ptr, count * sizeof(T));
}
}
};
template <typename T>
requires(std::is_trivial_v<T> && std::is_standard_layout_v<T>)
class DorisUniqueBufferPtr {
public:
using Deleter = DorisUniqueBufferDeleter<T>;
DorisUniqueBufferPtr() = default;
explicit DorisUniqueBufferPtr(T* ptr) = delete;
DorisUniqueBufferPtr(size_t size) {
DorisUniqueBufferDeleter<T> deleter(size);
void* buf = deleter.alloc(size * sizeof(T));
if (!buf) {
return;
}
T* arr = static_cast<T*>(buf);
ptr_ = std::unique_ptr<T[], DorisUniqueBufferDeleter<T>>(arr, std::move(deleter));
}
DorisUniqueBufferPtr(std::unique_ptr<T[], Deleter>&& uptr) : ptr_(std::move(uptr)) {}
DorisUniqueBufferPtr(DorisUniqueBufferPtr&& other) : ptr_(std::move(other.ptr_)) {}
DorisUniqueBufferPtr& operator=(DorisUniqueBufferPtr&& other) {
if (this != &other) {
ptr_ = std::move(other.ptr_);
}
return *this;
}
DorisUniqueBufferPtr(std::nullptr_t) noexcept {}
// Delete this function to avoid passing in a pointer allocated by other means(new/malloc).
void reset(T*) = delete;
bool operator==(std::nullptr_t) const noexcept { return ptr_ == nullptr; }
bool operator==(T* other) const noexcept { return ptr_.get() == other; }
void reset() noexcept { ptr_.reset(); }
auto release() noexcept { return ptr_.release(); }
T* get() const noexcept { return ptr_.get(); }
T& operator*() const noexcept { return *ptr_; }
T* operator->() const noexcept { return ptr_.get(); }
T& operator[](size_t i) const { return ptr_[i]; }
private:
std::unique_ptr<T[], Deleter> ptr_;
};
template <typename T>
requires(std::is_trivial_v<T> && std::is_standard_layout_v<T>)
DorisUniqueBufferPtr<T> make_unique_buffer(size_t n) {
return DorisUniqueBufferPtr<T>(n);
}
// NOTE: Even CustomStdAllocator 's allocate/dallocate could modify memory tracker,but it's still stateless,
// because threadcontext owns the memtracker, not CustomStdAllocator.
template <class T, typename MemoryAllocator>
class CustomStdAllocator : private MemoryAllocator {
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
CustomStdAllocator() noexcept = default;
template <class U>
struct rebind {
typedef CustomStdAllocator<U> other;
};
template <class Up>
CustomStdAllocator(const CustomStdAllocator<Up>&) noexcept {}
T* allocate(size_t n) { return static_cast<T*>(MemoryAllocator::alloc(n * sizeof(T))); }
void deallocate(T* ptr, size_t n) noexcept { MemoryAllocator::free((void*)ptr, n * sizeof(T)); }
size_t max_size() const noexcept { return size_t(~0) / sizeof(T); }
T* allocate(size_t n, const void*) { return allocate(n); }
// https://en.cppreference.com/w/cpp/memory/allocator/construct.html
// void construct( pointer p, const_reference val ); (1) (until C++11)
//
// template< class U, class... Args >
// void construct( U* p, Args&&... args ); (2) (since C++11)
// (deprecated in C++17)
// (removed in C++20)
// template <class Up, class... Args>
// void construct(Up* p, Args&&... args) {
// ::new ((void*)p) Up(std::forward<Args>(args)...);
// }
void destroy(T* p) { p->~T(); }
T* address(T& t) const noexcept { return std::addressof(t); }
T* address(const T& t) const noexcept { return std::addressof(t); }
};
template <class T, class Up>
bool operator==(const CustomStdAllocator<T>&, const CustomStdAllocator<Up>&) {
return true;
}
template <class T, class Up>
bool operator!=(const CustomStdAllocator<T>&, const CustomStdAllocator<Up>&) {
return false;
}
#include "common/compile_check_end.h"
} // namespace doris