Russian Qt Forum

Qt => Кладовая готовых решений => Тема начата: Igors от Ноябрь 06, 2015, 08:03



Название: Обертка контейнеров прямого доступа
Отправлено: Igors от Ноябрь 06, 2015, 08:03
Добрый день

Навеяно соседней темой. Работая с одними open-source увидел маленькую штучку, но очень она мне понравилась. Смысл: либе нужны исходные контейнеры/массивы (много). У пользователя эти данные есть, но в каком контейнере - хз. Может вектор, может дека, а может и просто массив. Перегонять из пользовательского контейнера в библиотечный утомительно. Вот класс решающий эту проблему
Код:
template <typename TYPE>
class Array {

public:
    typedef TYPE value_type;
    typedef int  size_type;

    typedef TYPE const& const_reference;
    typedef TYPE const* const_iterator;

    typedef TYPE& reference;
    typedef TYPE* iterator;

public:
    Array() : _begin(0), _size(0) { }
    Array(const Array<value_type>& array) : _begin(array._begin),
                                                  _size(array._size) { }
    Array(const value_type* ptr, size_type size) : _begin(const_cast<value_type*>(ptr)),
                                                      _size(size) { }
    ~Array() { }

    size_type size() const { return _size; }

    const_reference operator[](int index) const { return _begin[index]; }
    const_iterator  begin() const               { return _begin; }
    const_iterator  end() const                 { return _begin + _size; }

    reference operator[](int index) { return _begin[index]; }
    iterator  begin()               { return _begin; }
    iterator  end()                 { return _begin + _size; }

protected:
    value_type* _begin;
    size_type   _size;
};
Теперь все ф-ции либы работают с этим классом, ссылаясь на контейнеры юзера. Сам он данные не хранит, поэтому его можно создавать где и когда угодно, и из чего угодно. Удалять/вставлять он конечно не умеет - ну и ладно. Поюзал - очень удобно и просто, без всяких заумностей.
 


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 06, 2015, 08:36
Навеяно соседней темой. Работая с одними open-source увидел маленькую штучку, но очень она мне понравилась. Смысл: либе нужны исходные контейнеры/массивы (много). У пользователя эти данные есть, но в каком контейнере - хз. Может вектор, может дека, а может и просто массив. Перегонять из пользовательского контейнера в библиотечный утомительно. Вот класс решающий эту проблему
Эту проблему решают итераторы. :)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: ssoft от Ноябрь 06, 2015, 09:52
В данном случае Array - это обертка вокруг Raw массива, как раз для того, чтобы для него можно было использовать интерфейс итераторов.


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 06, 2015, 10:07
В данном случае Array - это обертка вокруг Raw массива, как раз для того, чтобы для него можно было использовать интерфейс итераторов.
Зачем?

Код
C++ (Qt)
int a[] = { 1, 2, 3, 4, 5 };
 
for( auto it = std::begin( a ); it != std::end( a ); ++it )
cout << *it << endl;
 
return 0;
 


Название: Re: Обертка контейнеров прямого доступа
Отправлено: ssoft от Ноябрь 06, 2015, 10:13
Это, скорее всего, из более раннего периода C++, когда отсутствовал auto в том виде, как он сейчас используется, и std::begin/std::end.


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 06, 2015, 10:16
Теперь все ф-ции либы работают с этим классом, ссылаясь на контейнеры юзера. Сам он данные не хранит, поэтому его можно создавать где и когда угодно, и из чего угодно. Удалять/вставлять он конечно не умеет - ну и ладно. Поюзал - очень удобно и просто, без всяких заумностей.
Кстати, можно мне рабочий пример использования этого чудо-класса с std::list? Ну или std::deque?


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Igors от Ноябрь 06, 2015, 10:42
Это, скорее всего, из более раннего периода C++, когда отсутствовал auto в том виде, как он сейчас используется, и std::begin/std::end.
Я ни разу не использовал итераторы с этим классом, хватает оператора []. Дело в другом, пример
Код
C++ (Qt)
void DoSomething( Type & a )
{
  for (auto it = std::begin(a)....
 
Какой тип должен быть у "a"? Придется объявлять эту ф-цию template, а за ней еще и еще, эта зараза мгновенно расползается. А вот с "Array" этого нет.


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 06, 2015, 10:45
Я ни разу не использовал итераторы с этим классом, хватает оператора [].
Хорошо, покажите как вы работали через этот класс с std::list или std::deque с помощью оператора []. Что бы это работало.


Название: Re: Обертка контейнеров прямого доступа
Отправлено: __Heaven__ от Ноябрь 06, 2015, 12:16
Приехали...
Код
C++ (Qt)
   const int a[] = {1, 2, 3, 4, 5};
   Array<int> wrapper(a, 5);
   wrapper[2] = 7;
 


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 06, 2015, 12:21
Приехали...
Код
C++ (Qt)
   const int a[] = {1, 2, 3, 4, 5};
   Array<int> wrapper(a, 5);
   wrapper[2] = 7;
 
Это что? :)



Название: Re: Обертка контейнеров прямого доступа
Отправлено: __Heaven__ от Ноябрь 06, 2015, 12:23
Это мы вносим изменения в массив констант :)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 06, 2015, 12:48
Это мы вносим изменения в массив констант :)
За const_cast нужно отдельно давать по рукам. :)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Igors от Ноябрь 06, 2015, 14:03
Это мы вносим изменения в массив констант :)
Не спешите стать (якобы) "знатоком" :) Этот класс сделан для ДЕЛА (а не для понтов). Да, он не готовит кофе, не жарит цыплят, и даже плюет на константность (что вообще-то нехорошо). Но он позволяет иметь под рукой "контейнер", что может оказаться куда более важным. Пример:
Код:
typedef Array<int> TIndexArray;

void CalcIndexHalfs( TIndexArray & arr )
{
   size_t half = arr.size() / 2;
   CalcOne(TIndexArray(&arr[0], half));
   CalcTwo(TIndexArray(&arr[half], arr.size() - half));
}
Да, того же можно достичь с autо (если не ошибаюсь, в С++ 14 он уже понимает "size"). Но так этот size надо таскать с собой (как счетчик для С массива) во всей цепи вызовов, а здесь все самодостаточно.

На мой взгляд, отличный пример профессионального подхода. Решается узкий круг задач - но предельно эффективно. А на обвинения "в недостатке общности" и.т.п. - да просто насрать (простите на грубом слове), у профи для этого времени нет  :)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 06, 2015, 14:14
Не спешите стать (якобы) "знатоком" :) Этот класс сделан для ДЕЛА (а не для понтов).
Не надо большими буквами писать слово ДЕЛО. Это не оправдывает того, что этот класс реализован с ошибками, которых можно было избежать.

На мой взгляд, отличный пример профессионального подхода. Решается узкий круг задач - но предельно эффективно. А на обвинения "в недостатке общности" и.т.п. - да просто насрать (простите на грубом слове), у профи для этого времени нет  :)
Вот вот. "Профи" спешат денег с заказчика побыстрей взять и насрать, что там будет завтра. :)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: __Heaven__ от Ноябрь 06, 2015, 14:16
Профи в чём?  ;D


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Авварон от Ноябрь 06, 2015, 14:21
std::array_view / std::string_view


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Igors от Ноябрь 07, 2015, 14:08
std::array_view
Какие-то следы в гугле есть, но в официальных справочниках (cppreference, cplusplus) такого нет.

Для интереса попробовал найти "где это в бусте". Побродил минут 10 по sub_array, array_view и assign - но пока ничего не понял. "Ишь ты какой, хотел за 10 минут все понять!". Ну а почему бы и нет если с либой мне хватило и 2? :) Вряд ли программисты далеко не бедной компании не знали о существовании подобного в std/boost, но они предпочли откровенный велосипед - и в этом есть немалые резоны.


Название: Re: Обертка контейнеров прямого доступа
Отправлено: m_ax от Ноябрь 07, 2015, 14:21
Цитировать
Вряд ли программисты далеко не бедной компании не знали о существовании подобного в std/boost, но они предпочли откровенный велосипед
Да-да, никрософт тож далекооо не бедная компания.. Теперь всё стало понятно)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Авварон от Ноябрь 07, 2015, 16:40
std::array_view / std::string_view

А хотя нет, глупость написал. array_view очень ограниченное применение имеет (вектор да массив). дек/кулист уже нельзя, так что это не то.
Тут тогда скорее range (пара итераторов) нужен.


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 07, 2015, 16:53
А хотя нет, глупость написал. array_view очень ограниченное применение имеет (вектор да массив). дек/кулист уже нельзя, так что это не то.
А решение выложенное Igors тоже умеет только вектор (который и так весь этот функционал имеет из коробки) да массив.
Заявленные в первом посте свойства не соответствуют действительности. :)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Igors от Ноябрь 08, 2015, 05:03
Тут тогда скорее range (пара итераторов) нужен.
Ну это уж точно должно быть в бусте! Открываем... пытаемся понять "концепт". Ну вроде слово "range" говорит само за себя, но как юзать - хз. Ладно, надо по примерам, гуглим "boost range example".. ага, эту ссылку мнооогие искали... ННу! Вот оно!
Код:
// Boost.Range library
//
//  Copyright Thorsten Ottosen 2003-2004. Use, modification and
//  distribution is subject to the Boost Software License, Version
//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see http://www.boost.org/libs/range/
//

#include <boost/detail/workaround.hpp>

#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
#  pragma warn -8091 // supress warning in Boost.Test
#  pragma warn -8057 // unused argument argc/argv in Boost.Test
#endif

#include <boost/range/functions.hpp>
#include <boost/range/metafunctions.hpp>
#include <boost/range/as_literal.hpp>
#include <boost/test/test_tools.hpp>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>

namespace
{
    //
    // example: extrating bounds in a generic algorithm
    //
    template< typename Range, typename T >
    inline typename boost::range_iterator<Range>::type
    find( Range& c, const T& value )
    {
       return std::find( boost::begin( c ), boost::end( c ), value );
    }
   
    template< typename Range, typename T >
    inline typename boost::range_iterator<Range>::type
    find( const Range& c, const T& value )
    {
       return std::find( boost::begin( c ), boost::end( c ), value );
    }
                   
    //
    // replace first value and return its index
    //                               
    template< class Range, class T >
    inline typename boost::range_difference<Range>::type
    my_generic_replace( Range& c, const T& value, const T& replacement )
    {
       typename boost::range_iterator<Range>::type found = find( c, value );
       
       if( found != boost::end( c ) )
           *found = replacement;
       return std::distance( boost::begin( c ), found );
    }                 
}


void check_algorithm()
{
    //
    // usage
    //
    const int N = 5;                     
    std::vector<int> my_vector;
    int values[] = { 1,2,3,4,5,6,7,8,9 };
    my_vector.assign( values, values + 9 );
    typedef std::vector<int>::iterator iterator;
    std::pair<iterator,iterator>       my_view( boost::begin( my_vector ),
                                                boost::begin( my_vector ) + N );
    BOOST_CHECK_EQUAL( my_generic_replace( my_vector, 4, 2 ), 3 );
    BOOST_CHECK_EQUAL( my_generic_replace( my_view, 4, 2 ), N );

}

#include <boost/test/unit_test.hpp>
using boost::unit_test::test_suite;

test_suite* init_unit_test_suite( int argc, char* argv[] )
{
    test_suite* test = BOOST_TEST_SUITE( "Range Test Suite" );

    test->add( BOOST_TEST_CASE( &check_algorithm ) );

    return test;
}
Мда.. и это еще самый короткий пример :)


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 08, 2015, 08:06
range это буквально пара итераторов:
first - начало последовательности
second - конец

Код
C++ (Qt)
typedef pair<iterator, iterator> range;
 


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Авварон от Ноябрь 08, 2015, 23:01
Ну это уж точно должно быть в бусте! Открываем... пытаемся понять "концепт". Ну вроде слово "range" говорит само за себя, но как юзать - хз. Ладно, надо по примерам, гуглим "boost range example".. ага, эту ссылку мнооогие искали... ННу! Вот оно!

хз насчет дуста, range library это один из пропозалов к каким-то будущим с++ (17?).


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Igors от Ноябрь 09, 2015, 08:01
Смысл в том что ф-ции/методы могут работать однообразно как со всем контейнером, так и с его частью. Иначе пришлось бы передавать индексы и/или пресловутые итераторы как аргументы, что довольно коряво.

Еще заметим что в Qt есть подобный класс QStringRef для эффективной работы со строками. И тоже никто не терзался "отсутствием общности" - заточен только на QString


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Old от Ноябрь 09, 2015, 08:22
Смысл в том что ф-ции/методы могут работать однообразно как со всем контейнером, так и с его частью. Иначе пришлось бы передавать индексы и/или пресловутые итераторы как аргументы, что довольно коряво.
Коряво использовать этот класс.
Он мало того, что опасен из-за неправильной работы с константными массивами, так и не позволяет работать ни с какими контейнерами, кроме непрерывного куска памяти. А пара итераторов прекрасно справляются с любыми контейнерами. Именно для обеспечения однообразия при работе с любыми контейнерами их и придумали.


Название: Re: Обертка контейнеров прямого доступа
Отправлено: Авварон от Ноябрь 09, 2015, 17:23
Еще заметим что в Qt есть подобный класс QStringRef для эффективной работы со строками. И тоже никто не терзался "отсутствием общности" - заточен только на QString

От него как раз хотят избавиться:)