• Implementing a two-way Turing Machine tape as an improvement to std::de

    From olcott@21:1/5 to All on Thu May 12 17:51:25 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    C/C++ people please critique this as the basis for an improvement to std::deque. It seems to have the key functionality of std::deque and
    does it much more simply while saving time and space. https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion
    tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--; Left.push_back(0); as needed
    void move_right(); // Tape_Head++; Left.push_back(0); as needed
    void Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
    tape_element Read() { return this->operator[](Tape_Head); };
    Tape_Type(){ Right.push_back('_'); } // constructor
    void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }



    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr Flibble@21:1/5 to olcott on Thu May 12 23:56:10 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an improvement to std::deque. It seems to have the key functionality of std::deque and
    does it much more simply while saving time and space. https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion
    tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--; Left.push_back(0); as needed
    void move_right(); // Tape_Head++; Left.push_back(0); as needed
    void Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
    tape_element Read() { return this->operator[](Tape_Head); };
    Tape_Type(){ Right.push_back('_'); } // constructor
    void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your
    specific use-case however it is NOT an improvement to std::deque for
    the general case -- see my reply in the other thread for why.

    /Flibble

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From olcott@21:1/5 to Mr Flibble on Thu May 12 18:09:39 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an improvement to
    std::deque. It seems to have the key functionality of std::deque and
    does it much more simply while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion
    tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--; Left.push_back(0); as needed
    void move_right(); // Tape_Head++; Left.push_back(0); as needed
    void Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
    tape_element Read() { return this->operator[](Tape_Head); };
    Tape_Type(){ Right.push_back('_'); } // constructor
    void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your
    specific use-case however it is NOT an improvement to std::deque for
    the general case -- see my reply in the other thread for why.

    /Flibble


    I didn't see any reason why it would not make a better std::deque.

    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr Flibble@21:1/5 to olcott on Fri May 13 00:22:18 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an improvement
    to std::deque. It seems to have the key functionality of
    std::deque and does it much more simply while saving time and
    space. https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion
    tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--; Left.push_back(0); as
    needed void move_right(); // Tape_Head++; Left.push_back(0);
    as needed void Write(tape_element Y){ this->operator[](Tape_Head)
    = Y; }; tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){ Right.push_back('_');
    } // constructor void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your
    specific use-case however it is NOT an improvement to std::deque for
    the general case -- see my reply in the other thread for why.

    /Flibble


    I didn't see any reason why it would not make a better std::deque.

    Because it doesn't meet the complexity and referential integrity
    requirements of std::deque.

    /Flibble

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Damon@21:1/5 to olcott on Thu May 12 19:23:47 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/12/22 6:51 PM, olcott wrote:
    C/C++ people please critique this as the basis for an improvement to std::deque. It seems to have the key functionality of std::deque and
    does it much more simply while saving time and space. https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
      int Tape_Head = 0;               // Can be negative
      std::vector<tape_element> Left;  // Stores left expansion
      std::vector<tape_element> Right; // Stores right expansion
      tape_element & operator[](int index);

    public:
      void move_left();      // Tape_Head--; Left.push_back(0); as needed
      void move_right();     // Tape_Head++; Left.push_back(0); as needed
      void Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
      tape_element Read()       { return this->operator[](Tape_Head); };
      Tape_Type(){ Right.push_back('_'); } // constructor
      void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
      if (index > 0)
        return Right[index];
      int Left_Index = ((index * -1) -1);
      return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
      printf("Tape_Type::Output()\n");

      if (Left.size())
      {
        int Last_One = Left.size() - 1;
        for (int N = Last_One; N >= 0; N--)
        {
          int TH = (N + 1) * -1; // determine Tape_Head from N
          printf("[%04d]:%c   Left[%02d]\n", TH, Left[N], N);
        }
      }
      if (Right.size())
        for (int N = 0; N < Right.size(); N++)
          printf("[%04d]:%c  Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
      Tape_Head--;
      int Left_Index = ((Tape_Head * -1) -1);
      if (Left_Index == Left.size())
        Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
      Tape_Head++;
      if (Tape_Head == Right.size())
        Right.push_back('_');
    }




    Looks at what indexing with an index value of 0 does.

    Operator [] want to test index >= 0, not > 0

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From olcott@21:1/5 to Richard Damon on Thu May 12 18:32:58 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/12/2022 6:23 PM, Richard Damon wrote:
    On 5/12/22 6:51 PM, olcott wrote:
    C/C++ people please critique this as the basis for an improvement to
    std::deque. It seems to have the key functionality of std::deque and
    does it much more simply while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
       int Tape_Head = 0;               // Can be negative
       std::vector<tape_element> Left;  // Stores left expansion
       std::vector<tape_element> Right; // Stores right expansion
       tape_element & operator[](int index);

    public:
       void move_left();      // Tape_Head--; Left.push_back(0); as needed
       void move_right();     // Tape_Head++; Left.push_back(0); as needed >>    void Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
       tape_element Read()       { return this->operator[](Tape_Head); };
       Tape_Type(){ Right.push_back('_'); } // constructor
       void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
       if (index > 0)
         return Right[index];
       int Left_Index = ((index * -1) -1);
       return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
       printf("Tape_Type::Output()\n");

       if (Left.size())
       {
         int Last_One = Left.size() - 1;
         for (int N = Last_One; N >= 0; N--)
         {
           int TH = (N + 1) * -1; // determine Tape_Head from N
           printf("[%04d]:%c   Left[%02d]\n", TH, Left[N], N);
         }
       }
       if (Right.size())
         for (int N = 0; N < Right.size(); N++)
           printf("[%04d]:%c  Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
       Tape_Head--;
       int Left_Index = ((Tape_Head * -1) -1);
       if (Left_Index == Left.size())
         Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
       Tape_Head++;
       if (Tape_Head == Right.size())
         Right.push_back('_');
    }




    Looks at what indexing with an index value of 0 does.

    Operator [] want to test index >= 0, not > 0

    Good catch. I just wrote that function as a simplification.

    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From olcott@21:1/5 to Mr Flibble on Thu May 12 18:38:49 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an improvement
    to std::deque. It seems to have the key functionality of
    std::deque and does it much more simply while saving time and
    space. https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion
    tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--; Left.push_back(0); as
    needed void move_right(); // Tape_Head++; Left.push_back(0);
    as needed void Write(tape_element Y){ this->operator[](Tape_Head)
    = Y; }; tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){ Right.push_back('_');
    } // constructor void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your
    specific use-case however it is NOT an improvement to std::deque for
    the general case -- see my reply in the other thread for why.

    /Flibble


    I didn't see any reason why it would not make a better std::deque.

    Because it doesn't meet the complexity and referential integrity
    requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has too many different meanings. invalidating iterators seemed to be what you mean
    otherwise I have no idea.

    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr Flibble@21:1/5 to olcott on Fri May 13 00:40:49 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an improvement
    to std::deque. It seems to have the key functionality of
    std::deque and does it much more simply while saving time and
    space. https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion
    tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--; Left.push_back(0); as
    needed void move_right(); // Tape_Head++; Left.push_back(0);
    as needed void Write(tape_element Y){ this->operator[](Tape_Head)
    = Y; }; tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your
    specific use-case however it is NOT an improvement to std::deque
    for the general case -- see my reply in the other thread for why.

    /Flibble


    I didn't see any reason why it would not make a better std::deque.


    Because it doesn't meet the complexity and referential integrity requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has too
    many different meanings. invalidating iterators seemed to be what you
    mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread. OK, I
    will repost why you are wrong here:

    * referential integrity and iterator invalidation are different
    things: when you add or remove elements to either end of a
    std::deque iterators are indeed invalidated however references to
    existing elements remain valid
    * If you do 1000 push_fronts followed by 1000 push_backs followed by
    1000 pop_fronts all is good however your next pop_front will have
    linear complexity, O(n), as it will necessitate removal of the first
    element of the right std::vector.

    /Flibble

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From olcott@21:1/5 to Mr Flibble on Thu May 12 18:49:43 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an improvement
    to std::deque. It seems to have the key functionality of
    std::deque and does it much more simply while saving time and
    space. https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion
    tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--; Left.push_back(0); as >>>>>> needed void move_right(); // Tape_Head++; Left.push_back(0);
    as needed void Write(tape_element Y){ this->operator[](Tape_Head)
    = Y; }; tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output();
    };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your
    specific use-case however it is NOT an improvement to std::deque
    for the general case -- see my reply in the other thread for why.

    /Flibble


    I didn't see any reason why it would not make a better std::deque.


    Because it doesn't meet the complexity and referential integrity
    requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has too
    many different meanings. invalidating iterators seemed to be what you
    mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread. OK, I
    will repost why you are wrong here:

    * referential integrity and iterator invalidation are different
    things: when you add or remove elements to either end of a
    std::deque iterators are indeed invalidated however references to
    existing elements remain valid

    Mine words the same way and has the added benefit of contiguous storage.

    * If you do 1000 push_fronts followed by 1000 push_backs followed by
    1000 pop_fronts all is good however your next pop_front will have
    linear complexity, O(n), as it will necessitate removal of the first
    element of the right std::vector.

    I don't think that this applies to the way that I implemented it.
    pop_front pops from the end of Left. pop_back pops from the end of
    Right. This is the key aspect that I used from David's two-stack approach.

    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr Flibble@21:1/5 to olcott on Fri May 13 00:53:40 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an
    improvement to std::deque. It seems to have the key
    functionality of std::deque and does it much more simply while
    saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right
    expansion tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); //
    Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
    tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N
    printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
    }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your
    specific use-case however it is NOT an improvement to std::deque
    for the general case -- see my reply in the other thread for
    why.

    /Flibble


    I didn't see any reason why it would not make a better
    std::deque.

    Because it doesn't meet the complexity and referential integrity
    requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has too
    many different meanings. invalidating iterators seemed to be what
    you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread. OK, I
    will repost why you are wrong here:

    * referential integrity and iterator invalidation are different
    things: when you add or remove elements to either end of a
    std::deque iterators are indeed invalidated however references
    to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous
    storage.

    * If you do 1000 push_fronts followed by 1000 push_backs followed
    by 1000 pop_fronts all is good however your next pop_front will have
    linear complexity, O(n), as it will necessitate removal of the
    first element of the right std::vector.

    I don't think that this applies to the way that I implemented it.
    pop_front pops from the end of Left. pop_back pops from the end of
    Right. This is the key aspect that I used from David's two-stack
    approach.

    Then it is totally different to what std::deque offers: std::deque
    allows ALL elements to be either popped from the front or back. Try
    reading AND UNDERSTANDING what I wrote again.

    /Flibble

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From olcott@21:1/5 to Mr Flibble on Thu May 12 19:12:22 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/12/2022 6:53 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an
    improvement to std::deque. It seems to have the key
    functionality of std::deque and does it much more simply while >>>>>>>> saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion >>>>>>>> std::vector<tape_element> Right; // Stores right
    expansion tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); //
    Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
    tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head from N >>>>>>>> printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N); >>>>>>>> }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], N); >>>>>>>> }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for your >>>>>>> specific use-case however it is NOT an improvement to std::deque >>>>>>> for the general case -- see my reply in the other thread for
    why.

    /Flibble


    I didn't see any reason why it would not make a better
    std::deque.

    Because it doesn't meet the complexity and referential integrity
    requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has too
    many different meanings. invalidating iterators seemed to be what
    you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread. OK, I
    will repost why you are wrong here:

    * referential integrity and iterator invalidation are different
    things: when you add or remove elements to either end of a
    std::deque iterators are indeed invalidated however references
    to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous
    storage.

    * If you do 1000 push_fronts followed by 1000 push_backs followed
    by 1000 pop_fronts all is good however your next pop_front will have
    linear complexity, O(n), as it will necessitate removal of the
    first element of the right std::vector.

    I don't think that this applies to the way that I implemented it.
    pop_front pops from the end of Left. pop_back pops from the end of
    Right. This is the key aspect that I used from David's two-stack
    approach.

    Then it is totally different to what std::deque offers: std::deque
    allows ALL elements to be either popped from the front or back. Try
    reading AND UNDERSTANDING what I wrote again.

    /Flibble


    I could allow all elements to be popped from the front or the back too.
    Mine is much faster when you need far less than all elements.

    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr Flibble@21:1/5 to olcott on Fri May 13 01:58:16 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On Thu, 12 May 2022 19:12:22 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:53 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an
    improvement to std::deque. It seems to have the key
    functionality of std::deque and does it much more simply
    while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left
    expansion std::vector<tape_element> Right; // Stores right
    expansion tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); //
    Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
    tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head
    from N printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
    }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N],
    N); }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for
    your specific use-case however it is NOT an improvement to
    std::deque for the general case -- see my reply in the other
    thread for why.

    /Flibble


    I didn't see any reason why it would not make a better
    std::deque.

    Because it doesn't meet the complexity and referential integrity
    requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has too
    many different meanings. invalidating iterators seemed to be what
    you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread.
    OK, I will repost why you are wrong here:

    * referential integrity and iterator invalidation are different
    things: when you add or remove elements to either end of a
    std::deque iterators are indeed invalidated however
    references to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous
    storage.

    * If you do 1000 push_fronts followed by 1000 push_backs
    followed by 1000 pop_fronts all is good however your next
    pop_front will have linear complexity, O(n), as it will
    necessitate removal of the first element of the right
    std::vector.

    I don't think that this applies to the way that I implemented it.
    pop_front pops from the end of Left. pop_back pops from the end of
    Right. This is the key aspect that I used from David's two-stack
    approach.

    Then it is totally different to what std::deque offers: std::deque
    allows ALL elements to be either popped from the front or back. Try reading AND UNDERSTANDING what I wrote again.

    /Flibble


    I could allow all elements to be popped from the front or the back
    too. Mine is much faster when you need far less than all elements.

    What you have does not offer what std::deque offers so is not
    equivalent to std::deque so can't be considered better than std::deque
    for the general case (I don't care about your specific use-case).

    /Flibble

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From olcott@21:1/5 to Mr Flibble on Thu May 12 20:34:41 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/12/2022 7:58 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 19:12:22 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:53 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an
    improvement to std::deque. It seems to have the key
    functionality of std::deque and does it much more simply
    while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative >>>>>>>>>> std::vector<tape_element> Left; // Stores left
    expansion std::vector<tape_element> Right; // Stores right >>>>>>>>>> expansion tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); //
    Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; }; >>>>>>>>>> tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); };

    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head
    from N printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N); >>>>>>>>>> }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], >>>>>>>>>> N); }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for
    your specific use-case however it is NOT an improvement to
    std::deque for the general case -- see my reply in the other >>>>>>>>> thread for why.

    /Flibble


    I didn't see any reason why it would not make a better
    std::deque.

    Because it doesn't meet the complexity and referential integrity >>>>>>> requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has too
    many different meanings. invalidating iterators seemed to be what
    you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread.
    OK, I will repost why you are wrong here:

    * referential integrity and iterator invalidation are different
    things: when you add or remove elements to either end of a
    std::deque iterators are indeed invalidated however
    references to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous
    storage.

    * If you do 1000 push_fronts followed by 1000 push_backs
    followed by 1000 pop_fronts all is good however your next
    pop_front will have linear complexity, O(n), as it will
    necessitate removal of the first element of the right
    std::vector.

    I don't think that this applies to the way that I implemented it.
    pop_front pops from the end of Left. pop_back pops from the end of
    Right. This is the key aspect that I used from David's two-stack
    approach.

    Then it is totally different to what std::deque offers: std::deque
    allows ALL elements to be either popped from the front or back. Try
    reading AND UNDERSTANDING what I wrote again.

    /Flibble


    I could allow all elements to be popped from the front or the back
    too. Mine is much faster when you need far less than all elements.

    What you have does not offer what std::deque offers so is not

    All these things can be added and we end up with a simple, faster,
    std:deque that has most the conventional overhead and complexity abolished.

    equivalent to std::deque so can't be considered better than std::deque
    for the general case (I don't care about your specific use-case).

    /Flibble


    It just a matter of defining more member functions.

    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From tth@21:1/5 to Mr Flibble on Fri May 13 09:10:24 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/13/22 09:02, Mr Flibble wrote:

    You cannot implement all of std::deque's member functions meeting
    std::deque requirements using your chosen data structure of two
    std::vectors.

    Not with any version of the C language.

    --
    +-------------------------------------------------------------------+
    | sphinx of black quartz, judge my vow. | +-------------------------------------------------------------------+

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr Flibble@21:1/5 to olcott on Fri May 13 08:02:47 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On Thu, 12 May 2022 20:34:41 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 7:58 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 19:12:22 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:53 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an
    improvement to std::deque. It seems to have the key
    functionality of std::deque and does it much more simply >>>>>>>>>> while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative >>>>>>>>>> std::vector<tape_element> Left; // Stores left
    expansion std::vector<tape_element> Right; // Stores right >>>>>>>>>> expansion tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); //
    Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; }; >>>>>>>>>> tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); }; >>>>>>>>>>
    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head >>>>>>>>>> from N printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N); >>>>>>>>>> }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], >>>>>>>>>> N); }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for >>>>>>>>> your specific use-case however it is NOT an improvement to >>>>>>>>> std::deque for the general case -- see my reply in the other >>>>>>>>> thread for why.

    /Flibble


    I didn't see any reason why it would not make a better
    std::deque.

    Because it doesn't meet the complexity and referential
    integrity requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has
    too many different meanings. invalidating iterators seemed to
    be what you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread.
    OK, I will repost why you are wrong here:

    * referential integrity and iterator invalidation are
    different things: when you add or remove elements to either end
    of a std::deque iterators are indeed invalidated however
    references to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous
    storage.

    * If you do 1000 push_fronts followed by 1000 push_backs
    followed by 1000 pop_fronts all is good however your next
    pop_front will have linear complexity, O(n), as it will
    necessitate removal of the first element of the right
    std::vector.

    I don't think that this applies to the way that I implemented it.
    pop_front pops from the end of Left. pop_back pops from the end
    of Right. This is the key aspect that I used from David's
    two-stack approach.

    Then it is totally different to what std::deque offers: std::deque
    allows ALL elements to be either popped from the front or back.
    Try reading AND UNDERSTANDING what I wrote again.

    /Flibble


    I could allow all elements to be popped from the front or the back
    too. Mine is much faster when you need far less than all elements.


    What you have does not offer what std::deque offers so is not

    All these things can be added and we end up with a simple, faster,
    std:deque that has most the conventional overhead and complexity
    abolished.

    equivalent to std::deque so can't be considered better than
    std::deque for the general case (I don't care about your specific use-case).

    /Flibble


    It just a matter of defining more member functions.

    You cannot implement all of std::deque's member functions meeting
    std::deque requirements using your chosen data structure of two
    std::vectors.

    /Flibble

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr Flibble@21:1/5 to olcott on Fri May 13 17:02:39 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On Fri, 13 May 2022 10:58:56 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/13/2022 2:02 AM, Mr Flibble wrote:
    On Thu, 12 May 2022 20:34:41 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 7:58 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 19:12:22 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:53 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an >>>>>>>>>>>> improvement to std::deque. It seems to have the key
    functionality of std::deque and does it much more simply >>>>>>>>>>>> while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be
    negative std::vector<tape_element> Left; // Stores left >>>>>>>>>>>> expansion std::vector<tape_element> Right; // Stores >>>>>>>>>>>> right expansion tape_element & operator[](int index); >>>>>>>>>>>>
    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); // >>>>>>>>>>>> Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; >>>>>>>>>>>> }; tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); }; >>>>>>>>>>>>
    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine
    Tape_Head from N printf("[%04d]:%c Left[%02d]\n", TH, >>>>>>>>>>>> Left[N], N); }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N,
    Right[N], N); }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque >>>>>>>>>>> for your specific use-case however it is NOT an
    improvement to std::deque for the general case -- see my >>>>>>>>>>> reply in the other thread for why.

    /Flibble


    I didn't see any reason why it would not make a better
    std::deque.

    Because it doesn't meet the complexity and referential
    integrity requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has >>>>>>>> too many different meanings. invalidating iterators seemed to >>>>>>>> be what you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread. >>>>>>> OK, I will repost why you are wrong here:

    * referential integrity and iterator invalidation are
    different things: when you add or remove elements to either
    end of a std::deque iterators are indeed invalidated however
    references to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous
    storage.

    * If you do 1000 push_fronts followed by 1000 push_backs
    followed by 1000 pop_fronts all is good however your next
    pop_front will have linear complexity, O(n), as it will
    necessitate removal of the first element of the right
    std::vector.

    I don't think that this applies to the way that I implemented
    it. pop_front pops from the end of Left. pop_back pops from
    the end of Right. This is the key aspect that I used from
    David's two-stack approach.

    Then it is totally different to what std::deque offers:
    std::deque allows ALL elements to be either popped from the
    front or back. Try reading AND UNDERSTANDING what I wrote again.

    /Flibble


    I could allow all elements to be popped from the front or the
    back too. Mine is much faster when you need far less than all
    elements.

    What you have does not offer what std::deque offers so is not

    All these things can be added and we end up with a simple, faster,
    std:deque that has most the conventional overhead and complexity
    abolished.

    equivalent to std::deque so can't be considered better than
    std::deque for the general case (I don't care about your specific
    use-case).

    /Flibble


    It just a matter of defining more member functions.

    You cannot implement all of std::deque's member functions meeting std::deque requirements using your chosen data structure of two std::vectors.

    /Flibble


    // Tape_Type implements a two-way Turing machine tape.
    // Right contains Tape_Head >= 0 values (right expansion)
    // Left contains Tape_Head < 0 values (left expansion)
    //
    // Grows with Right.push_back() as Tape_Head increases above 0.
    // Grows with Left.push_back() as Tape_Head decreases below 0.
    //
    // Tape_Type has functionality very similar to std::deque
    // yet implements this functionality much more simply.
    // This saves time and space.
    //
    class Tape_Type
    {
    public:
    typedef unsigned char tape_element;

    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion

    tape_element& operator[](int index)
    {
    return index >= 0 ? Right[index] : Left[-index - 1];
    }

    public:
    tape_element& front( ) { return Left.back(); }
    tape_element& back() { return Right.back(); }
    void pop_front() { Left.pop_back(); }
    void pop_back() { Right.pop_back(); }
    void push_front(tape_element& E) { Left.push_back(E); }
    void push_back(tape_element& E) { Right.push_back(E); }
    void reserve(unsigned int N)
    { Left.reserve(N); Right.reserve(N); }

    And what happens if Left is empty, Right is non-empty and you call
    pop_front()?

    /Flibble

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From olcott@21:1/5 to Mr Flibble on Fri May 13 10:58:56 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/13/2022 2:02 AM, Mr Flibble wrote:
    On Thu, 12 May 2022 20:34:41 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 7:58 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 19:12:22 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:53 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an
    improvement to std::deque. It seems to have the key
    functionality of std::deque and does it much more simply >>>>>>>>>>>> while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be negative >>>>>>>>>>>> std::vector<tape_element> Left; // Stores left >>>>>>>>>>>> expansion std::vector<tape_element> Right; // Stores right >>>>>>>>>>>> expansion tape_element & operator[](int index);

    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); // >>>>>>>>>>>> Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; }; >>>>>>>>>>>> tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); }; >>>>>>>>>>>>
    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine Tape_Head >>>>>>>>>>>> from N printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N); >>>>>>>>>>>> }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++)
    printf("[%04d]:%c Right[%02d]\n", N, Right[N], >>>>>>>>>>>> N); }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque for >>>>>>>>>>> your specific use-case however it is NOT an improvement to >>>>>>>>>>> std::deque for the general case -- see my reply in the other >>>>>>>>>>> thread for why.

    /Flibble


    I didn't see any reason why it would not make a better
    std::deque.

    Because it doesn't meet the complexity and referential
    integrity requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has
    too many different meanings. invalidating iterators seemed to
    be what you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread.
    OK, I will repost why you are wrong here:

    * referential integrity and iterator invalidation are
    different things: when you add or remove elements to either end
    of a std::deque iterators are indeed invalidated however
    references to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous
    storage.

    * If you do 1000 push_fronts followed by 1000 push_backs
    followed by 1000 pop_fronts all is good however your next
    pop_front will have linear complexity, O(n), as it will
    necessitate removal of the first element of the right
    std::vector.

    I don't think that this applies to the way that I implemented it.
    pop_front pops from the end of Left. pop_back pops from the end
    of Right. This is the key aspect that I used from David's
    two-stack approach.

    Then it is totally different to what std::deque offers: std::deque
    allows ALL elements to be either popped from the front or back.
    Try reading AND UNDERSTANDING what I wrote again.

    /Flibble


    I could allow all elements to be popped from the front or the back
    too. Mine is much faster when you need far less than all elements.


    What you have does not offer what std::deque offers so is not

    All these things can be added and we end up with a simple, faster,
    std:deque that has most the conventional overhead and complexity
    abolished.

    equivalent to std::deque so can't be considered better than
    std::deque for the general case (I don't care about your specific
    use-case).

    /Flibble


    It just a matter of defining more member functions.

    You cannot implement all of std::deque's member functions meeting
    std::deque requirements using your chosen data structure of two
    std::vectors.

    /Flibble


    // Tape_Type implements a two-way Turing machine tape.
    // Right contains Tape_Head >= 0 values (right expansion)
    // Left contains Tape_Head < 0 values (left expansion)
    //
    // Grows with Right.push_back() as Tape_Head increases above 0.
    // Grows with Left.push_back() as Tape_Head decreases below 0.
    //
    // Tape_Type has functionality very similar to std::deque
    // yet implements this functionality much more simply.
    // This saves time and space.
    //
    class Tape_Type
    {
    public:
    typedef unsigned char tape_element;

    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion

    tape_element& operator[](int index)
    {
    return index >= 0 ? Right[index] : Left[-index - 1];
    }

    public:
    tape_element& front( ) { return Left.back(); }
    tape_element& back() { return Right.back(); }
    void pop_front() { Left.pop_back(); }
    void pop_back() { Right.pop_back(); }
    void push_front(tape_element& E) { Left.push_back(E); }
    void push_back(tape_element& E) { Right.push_back(E); }
    void reserve(unsigned int N)
    { Left.reserve(N); Right.reserve(N); }



    --
    Copyright 2022 Pete Olcott

    "Talent hits a target no one else can hit;
    Genius hits a target no one else can see."
    Arthur Schopenhauer

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris M. Thomasson@21:1/5 to Mr Flibble on Fri May 13 12:44:05 2022
    XPost: comp.theory, comp.lang.c, comp.lang.c++

    On 5/13/2022 9:02 AM, Mr Flibble wrote:
    On Fri, 13 May 2022 10:58:56 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/13/2022 2:02 AM, Mr Flibble wrote:
    On Thu, 12 May 2022 20:34:41 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 7:58 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 19:12:22 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:53 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:49:43 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:40 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:38:49 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 6:22 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 18:09:39 -0500
    olcott <NoOne@NoWhere.com> wrote:

    On 5/12/2022 5:56 PM, Mr Flibble wrote:
    On Thu, 12 May 2022 17:51:25 -0500
    olcott <NoOne@NoWhere.com> wrote:

    C/C++ people please critique this as the basis for an >>>>>>>>>>>>>> improvement to std::deque. It seems to have the key >>>>>>>>>>>>>> functionality of std::deque and does it much more simply >>>>>>>>>>>>>> while saving time and space.
    https://www.cplusplus.com/reference/deque/deque/

    #define tape_element unsigned char

    class Tape_Type
    {
    private:
    int Tape_Head = 0; // Can be >>>>>>>>>>>>>> negative std::vector<tape_element> Left; // Stores left >>>>>>>>>>>>>> expansion std::vector<tape_element> Right; // Stores >>>>>>>>>>>>>> right expansion tape_element & operator[](int index); >>>>>>>>>>>>>>
    public:
    void move_left(); // Tape_Head--;
    Left.push_back(0); as needed void move_right(); // >>>>>>>>>>>>>> Tape_Head++; Left.push_back(0); as needed void
    Write(tape_element Y){ this->operator[](Tape_Head) = Y; >>>>>>>>>>>>>> }; tape_element Read() { return
    this->operator[](Tape_Head); }; Tape_Type(){
    Right.push_back('_'); } // constructor void Output(); }; >>>>>>>>>>>>>>
    tape_element& Tape_Type::operator[](int index)
    {
    if (index > 0)
    return Right[index];
    int Left_Index = ((index * -1) -1);
    return Left[Left_Index];
    }

    void Tape_Type::Output()
    {
    printf("Tape_Type::Output()\n");

    if (Left.size())
    {
    int Last_One = Left.size() - 1;
    for (int N = Last_One; N >= 0; N--)
    {
    int TH = (N + 1) * -1; // determine
    Tape_Head from N printf("[%04d]:%c Left[%02d]\n", TH, >>>>>>>>>>>>>> Left[N], N); }
    }
    if (Right.size())
    for (int N = 0; N < Right.size(); N++) >>>>>>>>>>>>>> printf("[%04d]:%c Right[%02d]\n", N, >>>>>>>>>>>>>> Right[N], N); }

    void Tape_Type::move_left()
    {
    Tape_Head--;
    int Left_Index = ((Tape_Head * -1) -1);
    if (Left_Index == Left.size())
    Left.push_back('_');
    }

    void Tape_Type::move_right()
    {
    Tape_Head++;
    if (Tape_Head == Right.size())
    Right.push_back('_');
    }

    It might be a more appropriate solution than std::deque >>>>>>>>>>>>> for your specific use-case however it is NOT an
    improvement to std::deque for the general case -- see my >>>>>>>>>>>>> reply in the other thread for why.

    /Flibble


    I didn't see any reason why it would not make a better >>>>>>>>>>>> std::deque.

    Because it doesn't meet the complexity and referential
    integrity requirements of std::deque.

    /Flibble


    It is faster then std::deque.
    I couldn't find what you mean by referential integrity it has >>>>>>>>>> too many different meanings. invalidating iterators seemed to >>>>>>>>>> be what you mean otherwise I have no idea.

    I see you are choosing to ignore my reply in the other thread. >>>>>>>>> OK, I will repost why you are wrong here:

    * referential integrity and iterator invalidation are
    different things: when you add or remove elements to either
    end of a std::deque iterators are indeed invalidated however >>>>>>>>> references to existing elements remain valid

    Mine words the same way and has the added benefit of contiguous >>>>>>>> storage.

    * If you do 1000 push_fronts followed by 1000 push_backs >>>>>>>>> followed by 1000 pop_fronts all is good however your next
    pop_front will have linear complexity, O(n), as it will
    necessitate removal of the first element of the right
    std::vector.

    I don't think that this applies to the way that I implemented
    it. pop_front pops from the end of Left. pop_back pops from
    the end of Right. This is the key aspect that I used from
    David's two-stack approach.

    Then it is totally different to what std::deque offers:
    std::deque allows ALL elements to be either popped from the
    front or back. Try reading AND UNDERSTANDING what I wrote again. >>>>>>>
    /Flibble


    I could allow all elements to be popped from the front or the
    back too. Mine is much faster when you need far less than all
    elements.

    What you have does not offer what std::deque offers so is not

    All these things can be added and we end up with a simple, faster,
    std:deque that has most the conventional overhead and complexity
    abolished.

    equivalent to std::deque so can't be considered better than
    std::deque for the general case (I don't care about your specific
    use-case).

    /Flibble


    It just a matter of defining more member functions.

    You cannot implement all of std::deque's member functions meeting
    std::deque requirements using your chosen data structure of two
    std::vectors.

    /Flibble


    // Tape_Type implements a two-way Turing machine tape.
    // Right contains Tape_Head >= 0 values (right expansion)
    // Left contains Tape_Head < 0 values (left expansion)
    //
    // Grows with Right.push_back() as Tape_Head increases above 0.
    // Grows with Left.push_back() as Tape_Head decreases below 0.
    //
    // Tape_Type has functionality very similar to std::deque
    // yet implements this functionality much more simply.
    // This saves time and space.
    //
    class Tape_Type
    {
    public:
    typedef unsigned char tape_element;

    private:
    int Tape_Head = 0; // Can be negative
    std::vector<tape_element> Left; // Stores left expansion
    std::vector<tape_element> Right; // Stores right expansion

    tape_element& operator[](int index)
    {
    return index >= 0 ? Right[index] : Left[-index - 1];
    }

    public:
    tape_element& front( ) { return Left.back(); }
    tape_element& back() { return Right.back(); }
    void pop_front() { Left.pop_back(); }
    void pop_back() { Right.pop_back(); }
    void push_front(tape_element& E) { Left.push_back(E); }
    void push_back(tape_element& E) { Right.push_back(E); }
    void reserve(unsigned int N)
    { Left.reserve(N); Right.reserve(N); }

    And what happens if Left is empty, Right is non-empty and you call pop_front()?


    Flip a coin; heads left, tails right.

    Heads, try to pop from left.
    Tails, try to pop from right.

    Just joking around here, in a sense... ;^)

    Actually, back in the day with my threading work, I have subdivided a
    lock-free stack into regions to amortize things. It was nothing like a
    deque. It was a long time ago, damn near 20 years. The cool part was
    that multiple threads could push/pop items without interfering with one
    another in a lot of use cases that respected locality. It was layered up:

    per-thread container
    hash bucket container
    global container

    Iirc, to pop an element from the container:

    check per-thread
    check hash bucket
    check the global

    if all checks fail, return nullptr, if not return the popped node.

    I think I might still have this code on an old hard drive.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)