Меньшие указатели ... возможно? (без системы с более низкой спецификацией) - PullRequest
8 голосов
/ 16 ноября 2011

В этой 2010 статье [1] о редких воксельных октавах (SVO) для радиовещания (извинения; загрузка бумаги занимает некоторое время), в разделе 3 указывается интересная настройкасэкономить место на данных вокселей, которые почти всегда очень велики.

Они указывают 15-битный относительный указатель с 1-битным флагом, чтобы указать, нужен ли дальний указатель (если объем данных слишком велик), флаг установлен, и считается, что 15-битный указатель указывает на вторичный дальний указатель.

Что делается для достижения этой цели?Это как-то связано с CUDA / GPU?Делается ли это через какой-то специальный распределитель, в коде C ++?

Как бы это было сделано в C ++, если вообще?

[1] Эффективный разреженный Voxel Octrees: Самули Лейн, Теро Каррас;NVIDIA Research

Ответы [ 4 ]

12 голосов
/ 16 ноября 2011

Ну, вы всегда можете вручную сохранить память в массиве и использовать целочисленные индексы в качестве «указателей».

8 голосов
/ 16 ноября 2011

В C / C ++ вы можете интерпретировать числа как указатели любым удобным для вас способом - но это означает, что вы не сможете просто разыменовывать / добавлять / вычитать и делать другие обычные операции с указателями.Вместо этого вам придется использовать функции, конвертирующие в «истинный» указатель, для выполнения таких операций.

В C ++ вы можете очень аккуратно обернуть все это внутри класса, который представляет интерфейс, похожий на указатель, реализуя1003 *, opeartor-> и арифметические операторы.

Так, на основе взгляда на рисунок 2, может выглядеть реализация предложенных указателей (обратите внимание, что если вы на самом деле делаете это, то вы 'мы хотим убедиться, что класс все равно не дополняется до 32 или 64 битов, и что они размещены на 2-байтовых границах - обычно для этого есть специфичные для компилятора директивы.)

class SmallChildPointer{
    public:
        SmallChildPointer(Child* bigChildPointer)
            : value(){
            ptrdiff_t offset = bigChildPointer - base_address;
            if(offset > 0x7fff)
                throw std::runtime_error("too big for a near pointer...");
            value = uint16_t(offset & 0x7fff);
        }

        Child* operator->() const{
            return (Child*)(base_address + value);
        }

        Child const& operator*() const{
            return *(Child const*)(base_address + value);
        }

        Child& operator*(){
            return *(Child*)(base_address + value);
        }

        // do this once, before constructing any of these!
        static void setTheGlobalBaseAddress(void* here){
             base_address = here;
        }

    private:
        uint16_t value;
        static void* base_address;
};
4 голосов
/ 16 ноября 2011

Вы заметили, что каждый из стандартных контейнеров принимает шаблон распределителя? Это так, что вы можете реализовать странные модели памяти, такие как описанные вами. (Или данные, которые находятся на другом компьютере по сети, или динамически рассчитываются ...) Да, лучший способ сделать это с помощью специального распределителя.

template<class T>
class linear_allocator  {
public:
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef T&& r_reference;
    typedef const T& const_reference;
    typedef T value_type;
    template<class _Other>
    struct rebind {
        typedef linear_allocator<_Other> other;
    };

    linear_allocatorr();
    linear_allocator(const linear_allocator<T>& b);
    linear_allocator(linear_allocator<T>&& b);
    template<class U>
    linear_allocator(const linear_allocator<U>& b);
    ~linear_allocator() throw();
    linear_allocator_base& operator=(const linear_allocator_base& b);
    pointer allocate(size_type count=1, pointer hint=nullptr);
    void deallocate(pointer ptr, size_type count=1) throw();
    static size_type max_size() throw();
    bool operator==(const linear_allocator_base& b) const throw();
    bool operator!=(const linear_allocator_base& b) const throw();
    static void construct(pointer ptr);
    static void construct(pointer ptr, const reference val);
    static void construct(pointer ptr, const r_reference val);
    template<class other>
    static void construct(pointer ptr, const other& val);
    template<class other>
    static void construct(pointer ptr, other&& val);
    //template<class ...Args>
    //static void construct(pointer ptr, Args args);
    static void destroy(pointer ptr);
    static pointer address(reference val) throw();
    static const_pointer address(const_reference val) throw();
    static linear_allocator<T> select_on_container_copy_construction();
    typedef std::false_type propagate_on_container_copy_assignment;
    typedef std::true_type propagate_on_container_move_assignment;
    typedef std::true_type propagate_on_container_swap;
};

Я не заметил, что пользовательский указатель (как у Autopulated) является наиболее важной частью. Пользовательский распределитель просто позволяет вам использовать стандартные контейнеры / алгоритмы / и т.д. с этими указателями.

0 голосов
/ 19 апреля 2018

Дополнительная опция: я нашел библиотеку с шаблонами на Github, которая выделяется из статического пула и может занимать всего 1 байт.

Имя библиотеки - "Маленький указатель" , а псевдоним участника - HDembinski.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...