LINUX.ORG.RU

Оптимизации в Common Lisp

 , , , , оптимизации


1

7

Пропиарю свой доклад вобщем-то, в том числе тут, потому что почему нет.

https://www.youtube.com/watch?v=5T-XONZCptc&t=16157s

Парни на Fprog/Tbilisi позвали рассказать, ну я вобщем-то рассказал.

Лисп можно докрутить до оптимизаций круче C++ на самом деле.

★★☆
Ответ на: комментарий от MOPKOBKA

C++ list не заглядывал

Это gnu реализация такая, у m$ там всё благообразнее и читабельнее.

// list standard header

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef _LIST_
#define _LIST_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <xmemory>

#if _HAS_CXX17
#include <xpolymorphic_allocator.h>
#endif // _HAS_CXX17

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
template <class _Mylist, class _Base = _Iterator_base0>
class _List_unchecked_const_iterator : public _Base {
public:
    using iterator_category = bidirectional_iterator_tag;

    using _Nodeptr        = typename _Mylist::_Nodeptr;
    using value_type      = typename _Mylist::value_type;
    using difference_type = typename _Mylist::difference_type;
    using pointer         = typename _Mylist::const_pointer;
    using reference       = const value_type&;

    _List_unchecked_const_iterator() noexcept : _Ptr() {}

    _List_unchecked_const_iterator(_Nodeptr _Pnode, const _Mylist* _Plist) noexcept : _Ptr(_Pnode) {
        this->_Adopt(_Plist);
    }

    _NODISCARD reference operator*() const noexcept {
        return _Ptr->_Myval;
    }

    _NODISCARD pointer operator->() const noexcept {
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _List_unchecked_const_iterator& operator++() noexcept {
        _Ptr = _Ptr->_Next;
        return *this;
    }

    _List_unchecked_const_iterator operator++(int) noexcept {
        _List_unchecked_const_iterator _Tmp = *this;
        _Ptr                                = _Ptr->_Next;
        return _Tmp;
    }

    _List_unchecked_const_iterator& operator--() noexcept {
        _Ptr = _Ptr->_Prev;
        return *this;
    }

    _List_unchecked_const_iterator operator--(int) noexcept {
        _List_unchecked_const_iterator _Tmp = *this;
        _Ptr                                = _Ptr->_Prev;
        return _Tmp;
    }

    _NODISCARD bool operator==(const _List_unchecked_const_iterator& _Right) const noexcept {
        return _Ptr == _Right._Ptr;
    }

#if !_HAS_CXX20
    _NODISCARD bool operator!=(const _List_unchecked_const_iterator& _Right) const noexcept {
        return !(*this == _Right);
    }
#endif // !_HAS_CXX20

    _Nodeptr _Ptr; // pointer to node
};

template <class _Mylist>
class _List_unchecked_iterator : public _List_unchecked_const_iterator<_Mylist> {
public:
    using _Mybase           = _List_unchecked_const_iterator<_Mylist>;
    using iterator_category = bidirectional_iterator_tag;

    using _Nodeptr        = typename _Mylist::_Nodeptr;
    using value_type      = typename _Mylist::value_type;
    using difference_type = typename _Mylist::difference_type;
    using pointer         = typename _Mylist::pointer;
    using reference       = value_type&;

    using _Mybase::_Mybase;

    _NODISCARD reference operator*() const noexcept {
        return const_cast<reference>(_Mybase::operator*());
    }

    _NODISCARD pointer operator->() const noexcept {
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _List_unchecked_iterator& operator++() noexcept {
        _Mybase::operator++();
        return *this;
    }

    _List_unchecked_iterator operator++(int) noexcept {
        _List_unchecked_iterator _Tmp = *this;
        _Mybase::operator++();
        return _Tmp;
    }

    _List_unchecked_iterator& operator--() noexcept {
        _Mybase::operator--();
        return *this;
    }

    _List_unchecked_iterator operator--(int) noexcept {
        _List_unchecked_iterator _Tmp = *this;
        _Mybase::operator--();
        return _Tmp;
    }
};

template <class _Mylist>
class _List_const_iterator : public _List_unchecked_const_iterator<_Mylist, _Iterator_base> {
public:
    using _Mybase           = _List_unchecked_const_iterator<_Mylist, _Iterator_base>;
    using iterator_category = bidirectional_iterator_tag;

    using _Nodeptr        = typename _Mylist::_Nodeptr;
    using value_type      = typename _Mylist::value_type;
    using difference_type = typename _Mylist::difference_type;
    using pointer         = typename _Mylist::const_pointer;
    using reference       = const value_type&;

    using _Mybase::_Mybase;

    _NODISCARD reference operator*() const noexcept {
#if _ITERATOR_DEBUG_LEVEL == 2
        const auto _Mycont = static_cast<const _Mylist*>(this->_Getcont());
        _STL_ASSERT(_Mycont, "cannot dereference value-initialized list iterator");
        _STL_VERIFY(this->_Ptr != _Mycont->_Myhead, "cannot dereference end list iterator");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        return this->_Ptr->_Myval;
    }

    _NODISCARD pointer operator->() const noexcept {
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _List_const_iterator& operator++() noexcept {
#if _ITERATOR_DEBUG_LEVEL == 2
        const auto _Mycont = static_cast<const _Mylist*>(this->_Getcont());
        _STL_ASSERT(_Mycont, "cannot increment value-initialized list iterator");
        _STL_VERIFY(this->_Ptr != _Mycont->_Myhead, "cannot increment end list iterator");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        this->_Ptr = this->_Ptr->_Next;
        return *this;
    }

    _List_const_iterator operator++(int) noexcept {
        _List_const_iterator _Tmp = *this;
        ++*this;
        return _Tmp;
    }

 //...
};

Ygor ★★★★★
()
Ответ на: комментарий от gaylord

Не, погоди. Вот у тебя два дерева: в одном string, в другом int. Что мешает мне вызвать функцию, которая получает int, на дерево, в котором string?

Несовместимый тип.

struct rbtree_c { ... };
void rbtree_c_set(
  struct rbtree_c *rb,
  const void *element,
  int element_size
);

template <typename T>
class rbtree<T> {
private:
  rbtree_c rb;
public:
  void set(const T* item) { rbtree_c_set(&rb, item, sizeof(T)); }
};

rbtree<int> rbtree_int;
rbtree_int.set("hello"); // error

Если ты шаблонизировал struct RBTree, зачем страдание с char *?

Это обвязка для вызовов, а не для структуры и ее основных методов. Пример выше. Про плюсы этого подхода я написал еще более выше.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от gaylord

Так я и так знаю ответ: тебе не нравятся шаблоны, ты знаешь только сишный препроцессор -> ты пользуешься только сишным процепроцессором.

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

alysnix ★★★
()
Ответ на: комментарий от MOPKOBKA

Это обвязка для вызовов, а не для структуры и ее основных методов. Пример выше. Про плюсы этого подхода я написал выше.

Так по сути ты уже получил все накладные расходы на парсинг шаблонов, что мог получить. Почему бы не сделать последний шаг T element?

gaylord
()
Ответ на: комментарий от alysnix

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

То, что я знаю, как это работает, не значит, что оно мне нравится. Удивительно, что такие вещи приходится объяснять.

gaylord
()
Ответ на: комментарий от gaylord

Это должно быстрее компилироваться, так как компилятору нужно воссоздать только шаблонные вызовы, а не структуры и методы.

Во вторых, как я писал выше, 1) компилятором код не будет дублироваться на каждый тип, 2) можно будет хранить элементы произвольного размера.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от gaylord

вы вообще странный. читаете хидеры фрибсд и топите за лисп. как вас там еще не разорвало пополам? таки куда тянет больше, в лисп или сишные хидеры?

alysnix ★★★
()
Ответ на: комментарий от alysnix

вы вообще странный. читаете хидеры фрибсд и топите за лисп

Я ещё ем баранину и пью кофе. Одеваю штаны и сушу волосы. Как эти вещи вообще друг с другом связаны в твоей голове?

P.S. И да, там был OpenBSD.

gaylord
()
Ответ на: комментарий от MOPKOBKA

Пункт 1 понимаю, пункта 2 не очень. T element позволяет хранить все, что описываемо T. Или ты про то, что в одной структуре можно хранить элементы разных типов?

gaylord
()
Ответ на: комментарий от gaylord

Или ты про то, что в одной структуре можно хранить элементы разных типов?

Да, разные типы. Ну или один тип разного размера если у него тоже есть flexiable member array. Если зашаблонить тип в структуру, то как потом выделять ноды с разным типом? Вроде никак.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от alysnix

ну и как они там , без шаблонов, этой «базы современного программирования»?

Они страдают с C и становятся все менее релевантными. Ничего нового.

gaylord
()
Ответ на: комментарий от MOPKOBKA

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

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

Правда неясно зачем все это делать, если есть шаблоны. Но никто не мешает заниматься обезьяньим трудом, если хочется.

gaylord
()
Ответ на: комментарий от gaylord

почему. это чисто оопэшный подход с максимальным реюзом кода, причем в его бинарном виде, а не в стыдливо визуальном, как у шаблонов. где любая закорюка может привести к совершенно безразмерным результатам.

alysnix ★★★
()
Ответ на: комментарий от MOPKOBKA

Вроде никак.

А может ещё так?

public class MultiArray {

    public static void main(String[] args) {
        var time = System.currentTimeMillis();
        String str = "test";
        int i = 0;
        var lst = new ArrayList<>();
        lst.add(str);
        lst.add(i);
        lst.add(time);
        for(var x: lst) System.out.println(x instanceof Object);
    }
}
Ygor ★★★★★
()
Ответ на: комментарий от alysnix

почему. это чисто оопэшный подход с максимальным реюзом кода, причем в его бинарном виде, а не в стыдливо визуальном, как у шаблонов. где любая закорюка может привести к совершенно безразмерным результатам.

О боги. Ладно, слава богу твоего кода мы никогда не увидим.

gaylord
()
Ответ на: комментарий от alysnix

По сравнению с моим подходом там будут ненужные виртуальные вызовы. У меня можно реализовать свой variant с одним switch вместо похождений по vtable.

MOPKOBKA ★★★★★
()
Ответ на: комментарий от MOPKOBKA

ненужные виртуальные вызовы.

они вообще ничего не стоят. особенно когда люди топят за лисп. там указатели и разыменования вдоль всего кода и поперек.

alysnix ★★★
()
Ответ на: комментарий от alysnix

Сколько работы, которую за программиста может сделать одно волшебное слово template… Такое ощущение, что тебе платят за количество набранных символов.

gaylord
()
Ответ на: комментарий от MOPKOBKA

Это ничего не значащая даже не мелочь. Выше просил по делу. Любой преобразователь синтаксиса тебе за пару секунд как хочешь представит. Та конвенция наименований нам не случайно и скриптами генерится

slew
()
Ответ на: комментарий от slew

Ну тогда все нравится, в принципе для любого кода нанимаешь преобразователя и он делает как надо.

MOPKOBKA ★★★★★
()
Ответ на: комментарий от gaylord

Сколько работы, которую за программиста может сделать одно волшебное слово template

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

хочу огорчить, но волшебное слово всю работу за программиста не сделает

Ну как же. Оно сделало всю ту работу, что ты собрался программировать руками. Серьезно, вот одним словом – раз, и готово. Автоматизация!

gaylord
()
Ответ на: комментарий от alysnix

тебе что в лиспе не нравится?

Мне все в нем нравится. Это первый ЯП на котором писать начинал. Вот только заикнись кому сейчас на работе про него, то или тупо вообще ничего не поймут, а те кто поймут, побегут дурку вызывать.

slew
()
Ответ на: комментарий от MOPKOBKA

А какие свойства от Lisp тут нужны?

В лиспе удобно написать совершенно однозначную функцию которая из списка входов постоянно делает список выходов. В простейшем случае входы-выходы тупо с логическими уровнями. В более сложном - наборы всякой накристальной периферии типа UART/PWM/ADC/DAC. Ну типа такое как бы очень навороченное FPGA в котором можно ещё и свои блоки делать. Работать оно может и не будет очень быстро, но однозначность привлекает, а скорость не всегда требуется.

Блоки как в GNU Radio это больше на какой-нибудь verilog похоже. Или если фантазия развита, то на любой SDK типа libopencm. Собираешь что тебе надо из кусочков, но клей приходится варить самому.

Stanson ★★★★★
()
Ответ на: комментарий от Stanson

Ничего не понятно, но очень интересно…

В лиспе удобно написать совершенно однозначную функцию которая из списка входов постоянно делает список выходов

а на си эту «совершенно однозначную функцию» сделать нельзя что-ли?

alysnix ★★★
()
Ответ на: комментарий от alysnix

а на си эту «совершенно однозначную функцию» сделать нельзя что-ли?

Можно, но однозначность будет под вопросом, если функция достаточно сложная. Чтобы убедиться в однозначности императивщины придётся проверить абсолютно все комбинации входных состояний, и этих комбинаций могут быть миллиарды. Ну или при написании просто получится кусок лиспа, т.е. произойдёт переизобретение велосипеда.

Функциональщина далеко не во всех случаях применима, разумеется, но там где её применять уместно, она неплохо справляется.

Stanson ★★★★★
()
Ответ на: комментарий от anonymous

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

Stanson ★★★★★
()
Ответ на: комментарий от Stanson

Если все будут придумывать термины как ты, то люди просто перестанут понимать друг друга. Если тебе не нравится термин, то тогда бог с тобой!

По мне так нормальный термин. Тут еще крутится «ссылочная прозрачность». Тоже заумно звучит, но если разобраться, то вполне понятная концепция, особенно в свете рассмотрения ленивости в языке. Я даже не знаю, как ты их назвал бы - теряюсь в догадках)

Похоже, что зря я сюда заглянул за ответом. Ожидал большего

anonymous
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.