Generic Class Library - bugs, description, questions, usage and suggestions - page 29

 
Alexey Volchanskiy:

MSDN calls it a ring buffer, I didn't come up with the name.

link to the

Alexey Navoykov:

...and ending with a conversion to arguments by reference, not just by value.

there may be a problem with the literals

 
TheXpert:

link in the studio

There may be a problem with literals

Lazy to search for that article again, but I've stretched it a bit. A ring single or double linked list is based on a linked list, but the last element stores a link to the very first one.

 
TheXpert:

there may be problems with the literals

No, I have the "values" class inherited from the base "reference" class, purely as a wrapper. So just select the required version of the class - and go
 
Alexey Volchanskiy:

A single or double linked list is based on a linked list, but the last item in the linked list stores a link to the very first item.

That's the point: it's a "base" one, not a replacement one. No one has stopped the developers from making it an additional container here as well. Instead of substituting common concepts
 
Alexey Navoykov:

Most likely, whoever ported these classes just decided to simplify his life by simplifying code. Instead of two pointers m_first and m_last he made one pointer m_head...

Looked at the dotnet sources, and realized the reason. The LinkedList class itself is ported correctly, there's really only one pointer head, which is both the start and the end. So the internal implementation is indeed looped, but the external behavior is not. MQ has an error in the CLinkedNode class (Next and Previous methods). Here's what their original implementation looks like:

        public LinkedListNode<T>? Next
        {
            get { return next == null || next == list!.head ? null : next; }
        }

        public LinkedListNode<T>? Previous
        {
            get { return prev == null || this == list!.head ? null : prev; }
        }

And here's how it's ported to MQL:

   CLinkedListNode<T>* Next(void)                      { return(m_next); }
   CLinkedListNode<T>* Previous(void)                  { return(m_prev); }

Maybe they were inattentive and got it wrong.

But in general I'm also a bit surprised about the dotnet implementation. Why wasn't it possible to make two pointers in the list itself (first and last) instead of one head. That would avoid extra checks in above methods of list node, i.e. they would look exactly like MQ now, but everything would work properly. Of course, it would slow down a bit the process of nodes insertion/deletion, but it would speed up iteration over them, which is a much higher priority. Next and Previous are definitely called more often, than added nodes. That's how I did it, I thought the same would be true for melkomsoft. But never mind )

By the way, MQ has another bug in implementation of CLinkedListNode and CRedBlackTreeNode. (except m_value) are intended to be changed solely by the list class itself. No one else has to change them. That's why they are internal fields in dotnet. MQ has created public methods to modify these fields, and at least they would have given them a specific name... but no, just the usual names:

void              Next(CLinkedListNode<T>*value)     { m_next=value; }
 

Hi all!

Is there any other way to delete items in CHashMap other than copying them via CopyTo and manually deleting them?

 

Here are a couple of other things to sink the furnace of the library's poor implementation. Their class CKeyValuePair inherits IComparable interface (and therefore IEqualityComparable too) for some reason, requiring that user type Key should support these interfaces too. Although there's no need in it if we define our own Comparer. In the original one KeyValuePair has no interfaces of course.

If you keep poking around, you'll find even stranger things:

template<typename TKey,typename TVal>
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
                                                      m_free_list(0),
                                                      m_free_count(0),
                                                      m_capacity(0)
  {
//--- check equality comaprer
   if(CheckPointer(comparer)==POINTER_INVALID)
     {
      //--- use default equality comaprer    
      m_comparer=new CDefaultEqualityComparer<TKey>();
      m_delete_comparer=true;
     }
   else
     {
      //--- use specified equality comaprer
      m_comparer=comparer;
      m_delete_comparer=false;
     }
  }

I.e. if you pass a broken pointer into the constructor accidentally, the program will not only continue working in peace but its logic will change, too!

The constructor should look like this:

template<typename TKey,typename TVal>
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
                                                      m_free_list(0),
                                                      m_free_count(0),
                                                      m_capacity(0),
                                                      m_comparer(comparer),
                                                      m_delete_comparer(false)
{ }

And noPOINTER_INVALID . And there is a different constructor signature for the default comparer.

 
Is there an example of how to correctly apply a CQueue<T> template with an arbitrary class as the T parameter ?
 
Already been in a parallel thread. Ask for a ban.
 

Can you tell me why the code doesn't compile?

#include <Generic\HashMap.mqh>
void OnStart()
  {
   CHashMap<ENUM_CHART_PROPERTY_INTEGER,int> mapI;    // эта срока компилируется без ошибок
   CHashMap<ENUM_CHART_PROPERTY_DOUBLE,double> mapD;  // здесь ошибки компиляции: 'NULL' - cannot convert enum  HashMap.mqh     21      39. 'NULL' - cannot convert enum        HashMap.mqh     462     30
   CHashMap<ENUM_CHART_PROPERTY_STRING,string> mapS;  // здесь ошибки компиляции: 'NULL' - cannot convert enum  HashMap.mqh     21      39. 'NULL' - cannot convert enum        HashMap.mqh     462     30

  }

The problem is in system enums: ENUM_CHART_PROPERTY_DOUBLE, ENUM_CHART_PROPERTY_STRING something is wrong with them. If I use my own enum as a key type, the compilation works too.