Iterator etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Iterator etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

12 Ekim 2015 Pazartesi

GoF - Iterator Örüntüsü

Iterator - Davranışsal Örüntü
Iterator ve Visitor birbirlerine zıt tasarım örüntüleri. Iterator pull,Visitor ise push modunda çalışıyor diye düşünülebilir.
"The iterator pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation"
Veri Yapısını Döndürmek
Iterator tasarım örüntüsü, veri yapımızın kendisi veya kalıttığı arayüzü (örneğin IList) döndüren bir metod yerine iterator döndüren metodlar kullanmayı öneriyor. IList döndürent metodlar Java dünyasında çok yaygın. C# dünyasında ise IEnumerator döndüren metodlar biraz daha yaygın.

Iterator döndürmek istersek çeşitli programla dillerinde kullanılan örnekler şöyle:

Java
Iterator Arayüzü ile sağlanıyor.

C#
IEnumerable Arayüzü ile sağlanıyor.

C++
Veri yapımızın iterator tipini typedef veya using ile dış dünyaya açarız. begin(),end() ve bunların const türevlerini gerçekleştiren metodlar sunarız.
Örnek
class AddressBook
{
  using peoples_t = std::vector<People>;
public:
  using iterator = peoples_t::iterator;
  using const_iterator = peoples_t::const_iterator;

  AddressBook();

  iterator begin() { return people.begin(); }
  iterator end() { return people.end(); }
  const_iterator begin() const { return people.begin(); }
  const_iterator end() const { return people.end(); }
  const_iterator cbegin() const { return people.cbegin(); }
  const_iterator cend() const { return people.cend(); }

private:
  peoples_t people;
};


25 Ağustos 2015 Salı

STL Stream Iteratorleri

Giriş
Iteratorler veriyapıları üzerinde yürümek için kullanılırlar. Ancak STL stream (akım) ile iteratorleri birleştirmemizi sağlayan adaptor şeklinde iteratorler de sağlıyor.

Genellikle std::copy veya std::transform algoritmaları ile kullanılırlar

istream_iterator sınıfı
istream_iterator yazısına taşıdım.

ostream_iterator
Akıma yazma yapmayı sağlar.

C array'ini yazma örneği
std::copy(std::begin(a), std::end(a),
    std::ostream_iterator<int>(std::cout, " "));
STL Veriyapısına yazma örneği
std::copy(a.begin(), a.end(),
    std::ostream_iterator<int>(std::cout, " "));
Cout'a yazmak örneği
std::ostream_iterator<int, char> out_iter2(std::cout, " " );
std::transform(osd.begin(), 
               osd.end(), 
               out_iter2, 
               [] (int* x) { return *x; }
              );




23 Kasım 2014 Pazar

STL Iterator'leri

Giriş
Iterator'ler her veri yapısında bulunuyorlar. Java ve C# gibi dillerden farklı olarak iterator'lerin çeşitleri var. Aşağıda konu ile ilgili notlarım bulunuyor.

Not : Konuyla ilgili olarak STL Stream Iteratorleri başlıklı yazıya da göz atabilirsiniz.

Iteratörler 
iterator ve end()
end() ile elde edilen nokta veriyapısının en son elemanından bir sonraki bir şeydir.Dolayısıyla her veriyapısı [begin,end) şeklinde yarı açık bir aralık verir. Aşağıdaki şekilde durum görülebilir.

Benzer bir şekil ise aşağıda.

Dolayısıyla end() ile verilen iterator'ü bir kere daha artırmaya çalışmak tanımsız davranıştır.

Bu yarı açık aralık yüzünden aşağıdaki döngü çalışır.
for (auto it = v.begin(); it != v.end(); ++it)
iterator ve erase
Bir çok STL veri yapısı için (özellikle vector için) yapıyı dolaşırken silme işlemi aşağıdaki gibi olur.
for (it = begin(); it != end(); ) {
    if (...) it = index.erase(it);
    else ++it;
}
List'te aynı şekilde çalışır. Örnek:


list<A*> myList;
list<A*>::iterator it = myList.begin();
while( it != myList.end() ) {
    (*it)->DoSomething();
    if( (*it)->WorksFnished() ) {
        it = myList.erase(it);
    } else {
        ++it;
    }
}
Burada if koşulundan sonra iterator'ün erase metodunun döndürdüğü değere eşitlendiğine dikkat etmek lazım.
erase metodu silinen elemandan bir sonraki elemanı gösteren değeri döndürür. iterator bu yeni değere eşitlendiği için ++ ile ilerletilmesi gerekmez. 

Iterator Tanımlama
İki çeşit iterator tanımlama yöntemi mevcut. İlk yöntemde iterator sınıfı veri yapısı sınıfına friend olarak tanıtılıyor. Böylece iterator veriyapısının rahatça dolaşabiliyor. STL iteratorleri bu yöntemi kullanıyorlar.Örnek:
class MyClass
{
    friend class MyClassIterator;
 private:
    Node* m_PrivateData;
}
Diğer yöntemde ise Iterator veriyapısına kendini geçerek, kullanacağı index'i veriyapısının güncellemesini istiyor.

Burada her veri yapısının Iterable arayüzünden türediği farz ediliyor. Iterable arayüzü AdvanceIterator(), GetCurrentValue() gibi arayüzler sunuyor.

Template kullanılamayan projelerde, Nesneye Yönelimli bir tasarım yapmak için bu yöntem kullanılabilir.Örnek:
bool Iterator::MoveNext()
{
    return m_pIterable->AdvanceIterator(this);
}
void* Iterator::CurrentItemValue()
{
    return m_pIterable->GetCurrentValue(this);
}
InputIterator
InputIterator yazısına taşıdım.

OutputIterator
OutputIterator yazısına taşıdım.

Random Access Iterator
Random Access Iterator sınıfı diğer iteratör sınıflarına göre en fazla özelliği sunan sınıftır. 
Vector gibi sınıfların döndürdüğü iteratorler random acces iterator olarak sınıflandırılıyor.Bu tür iteratörler "<" , "<=", ">", ">=" gibi karşılaştırmaları desteklerler. Örnek:
for(vector<int>::iterator it = myvector.begin(); it < myvector.end(); it++){
    // some code
}
Reverse Iterator
Reverse Iterator alt tarafata, ileriye doğru çalışan bir iterator'ü kullanarak çalışır. Bu yüzden base()diye bir metodu vardır.
base
Bu metod ile dikkat edilmesi gereken nokta, bir reverse iterator'de *it ve it farklı yerleri işaret ederler. Şekilde görülebilir.

Örnek:
  
  

Türetilen Iterator Fikirleri
Bir çok kütüphane kendi iterator uzantılarını sunuyor. Burada bazı iterator fikirleri var. 
Arka arkaya aynı değer varsa sadece birini dönen deduplication iterator.

Iterator Traits
iterator_traits yazısına taşıdım.