Библиотека Generic классов - ошибки, описание, вопросы, особенности использования и предложения - страница 22

 
Alexey Navoykov:

Видимо вы имеете ввиду не наследование, а обёртку из класса над структурой?

ну да.
 
//+------------------------------------------------------------------+
//| Determines whether a set contains the specified element.         |
//+------------------------------------------------------------------+
template<typename T>
bool CHashSet::Contains(T item)
  {
//--- check buckets
   if(ArraySize(m_buckets)!=0)
     {
      //--- get hash code for item      
      int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF;
      //--- search item in the slots       
      for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next)
         if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item))
            return(true);
     }
   return(false);
  }

Для чего знаковый бит обрезается?

 
fxsaber:

Для чего знаковый бит обрезается?

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

 
TheXpert:

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

uint?

 
fxsaber:

uint?

нет смысла

Документация по MQL5: Операции с массивами / ArraySize
Документация по MQL5: Операции с массивами / ArraySize
  • www.mql5.com
"Нулевое измерение = Размер массива / (Первое измерение * Второе измерение * Третье измерение)"
 
TheXpert:

нет смысла

Сочетание выделенных строк видится ошибочным

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотека Generic классов - ошибки, описание, вопросы, особенности использования и предложения

fxsaber, 2018.06.11 20:04

//+------------------------------------------------------------------+
//| Determines whether a set contains the specified element.         |
//+------------------------------------------------------------------+
template<typename T>
bool CHashSet::Contains(T item)
  {
//--- check buckets
   if(ArraySize(m_buckets)!=0)
     {
      //--- get hash code for item      
      int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF;
      //--- search item in the slots       
      for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next)
         if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item))
            return(true);
     }
   return(false);
  }

Как можно сравнивать обрезанный хэш с хэшем без обрезания?

 
fxsaber:

Как можно сравнивать обрезанный хэш с хэшем без обрезания?

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

посмотрите код добавления элемента

 
TheXpert:

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

посмотрите код добавления элемента

//+------------------------------------------------------------------+
//| Insert the value with the specified key from the map.            |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CHashMap::Insert(TKey key,TValue value,const bool add)
  {
   if(m_capacity==0)
      Initialize(0);
//--- get hash code from key
   int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
   int target_bucket=hash_code%m_capacity;
//--- collisions count in one bucket with different hashes
   int collision_count=0;
//--- search pair with specified key
   for(int i=m_buckets[target_bucket]; i>=0; i=m_entries[i].next)
     {
      //--- hash compare      
      if(m_entries[i].hash_code!=hash_code)
        {
         collision_count++;
         continue;
        }
      //--- value compare     
      if(m_comparer.Equals(m_entries[i].key,key))
        {
         //--- adding duplicate
         if(add)
            return(false);
         m_entries[i].value=value;
         return(true);
        }
     }
//--- check collision
   if(collision_count>=m_collision_threshold)
     {
      int new_size=CPrimeGenerator::ExpandPrime(m_count);
      Resize(new_size);
     }
//--- calculate index
   int index;
   if(m_free_count>0)
     {
      index=m_free_list;
      m_free_list=m_entries[index].next;
      m_free_count--;
     }
   else
     {
      if(m_count==ArraySize(m_entries))
        {
         int new_size=CPrimeGenerator::ExpandPrime(m_count);
         Resize(new_size);
         target_bucket=hash_code%new_size;
        }
      index=m_count;
      m_count++;
     }
//--- set pair
   m_entries[index].hash_code=hash_code;
   m_entries[index].next=m_buckets[target_bucket];
   m_entries[index].key=key;
   m_entries[index].value=value;
   m_buckets[target_bucket]=index;
   return(true);
  }

Да, спасибо, не обрезанных по коду просто нет. Странно, что в самом методе HashCode обрезание не сделали. Видимо, расчет был на защиту от дурака (кривые кастомные хэши).

 

Извините если уже было. Не нашел в документации.

А есть ли какойлибо цикл по Set-ам? итератор?

 
Viktor Lubimov:

Извините если уже было. Не нашел в документации.

А есть ли какойлибо цикл по Set-ам? итератор?

К сожалению нет.
Но можно самому реализовать. 
Вот, например, можете посмотреть пример из статьи РЕЦЕПТЫ MQL5 - РЕАЛИЗУЕМ АССОЦИАТИВНЫЙ МАССИВ ИЛИ СЛОВАРЬ ДЛЯ БЫСТРОГО ДОСТУПА К ДАННЫМ

void ReverseEnumerateAll(CList& list)
{
   CObject* node = list.GetLastNode();
   for(int i = list.Total()-1; node != NULL; i--, node = node.Prev())
      printf("Element at " + (string)i); 
}
Как работает этот код? На самом деле все просто. В функции EnumerateAll() в самом начале мы получаем ссылку на первый узел. Затем в цикле for мы печатаем порядковый узел этого узла 
и переходим к следующему узлу командой node = node.Next(), не забывая при этом проитерировать текущий индекс элемента на единицу (i++). Перебор продолжается до тех пор, пока текущий 
узел node не станет равен NULL, за это ответствен код во втором блоке for: node != NULL.

Аналогично работает реверсивная версия этой функции ReverseEnumerateAll() с той лишь разницей, что она вначале получает последний элемент списка CObject* node = list.GetLastNode(). 
В цикле for она получает не следующий, а предыдущий элемент списка node = node.Prev().
Причина обращения: