Task: Stream merge


C++: 
#include <iostream>
#include <vector>

template <typename C, typename A>
void merge2(const C& c1, const C& c2, const A& action) {
    auto i1 = std::cbegin(c1);
    auto i2 = std::cbegin(c2);

    while (i1 != std::cend(c1) && i2 != std::cend(c2)) {
        if (*i1 <= *i2) {
            action(*i1);
            i1 = std::next(i1);
        } else {
            action(*i2);
            i2 = std::next(i2);
        }
    }
    while (i1 != std::cend(c1)) {
        action(*i1);
        i1 = std::next(i1);
    }
    while (i2 != std::cend(c2)) {
        action(*i2);
        i2 = std::next(i2);
    }
}

template <typename A, typename C>
void mergeN(const A& action, std::initializer_list<C> all) {
    using I = typename C::const_iterator;
    using R = std::pair<I, I>;

    std::vector<R> vit;
    for (auto& c : all) {
        auto p = std::make_pair(std::cbegin(c), std::cend(c));
        vit.push_back(p);
    }

    bool done;
    R* least;
    do {
        done = true;

        auto it = vit.begin();
        auto end = vit.end();
        least = nullptr;

        
        while (it != end && it->first == it->second) {
            it++;
        }
        if (it != end) {
            least = &(*it);
        }
        while (it != end) {
            
            while (it != end && it->first == it->second) {
                it++;
            }
            if (least != nullptr && it != end
                && it->first != it->second
                && *(it->first) < *(least->first)) {
                
                least = &(*it);
            }
            if (it != end) {
                it++;
            }
        }
        if (least != nullptr && least->first != least->second) {
            done = false;
            action(*(least->first));
            least->first = std::next(least->first);
        }
    } while (!done);
}

void display(int num) {
    std::cout << num << ' ';
}

int main() {
    std::vector<int> v1{ 0, 3, 6 };
    std::vector<int> v2{ 1, 4, 7 };
    std::vector<int> v3{ 2, 5, 8 };

    merge2(v2, v1, display);
    std::cout << '\n';

    mergeN(display, { v1 });
    std::cout << '\n';

    mergeN(display, { v3, v2, v1 });
    std::cout << '\n';
}









Fortran:       SUBROUTINE FILEMERGE(N,INF,OUTF)	
       INTEGER N	
       INTEGER INF(*)	
       INTEGER OUTF	
       INTEGER L(N)	
       INTEGER LIST(0:N)
       LOGICAL LIVE(N)	
       INTEGER ENUFF		
       PARAMETER (ENUFF = 666)	
       CHARACTER*(ENUFF) AREC(N)
       INTEGER I,IT	
        LIST = 0	
        LIVE = .TRUE.	
Charge the battery.
        DO I = 1,N	
          CALL GRAB(I)		
        END DO		
Chug away.
        DO WHILE(LIST(0).GT.0)	
          IT = LIST(0)		
          WRITE (OUTF,"(A)") AREC(IT)(1:L(IT))	
          LIST(0) = LIST(IT)	
          CALL GRAB(IT)		
        END DO			

       CONTAINS	
        SUBROUTINE GRAB(IN)	
         INTEGER IN		
         INTEGER IT,P		
          IF (.NOT.LIVE(IN)) RETURN	
          READ (INF(IN),1,END = 10) L(IN),AREC(IN)(1:MIN(ENUFF,L(IN)))	
    1     FORMAT (Q,A)		
Consider the place of AREC(IN) in the LIST. Entry LIST(IN) is to be linked back in.
          P = 0		
    2     IT = LIST(P)		
          IF (IT.GT.0) THEN	
            IF (AREC(IN)(1:L(IN)).GT.AREC(IT)(1:L(IT))) THEN	
              P = IT			
              GO TO 2			
            END IF		
          END IF	
          LIST(IN) = IT		
          LIST(P) = IN		
          RETURN	
   10     LIVE(IN) = .FALSE.	
          LIST(IN) = -666	
        END SUBROUTINE GRAB	
      END SUBROUTINE FILEMERGE	

      PROGRAM MASH
      INTEGER MANY
      PARAMETER (MANY = 4)	
      INTEGER FI(MANY)
      CHARACTER*(28) FNAME(MANY)
      DATA FNAME/"FileAppend.for","FileChop.for",
     1 "FileExt.for","FileHack.for"/
      INTEGER I,F

      F = 10	
      OPEN (F,FILE="Merged.txt",STATUS="REPLACE",ACTION="WRITE")	
      DO I = 1,MANY	
        FI(I) = F + I		
        OPEN (FI(I),FILE=FNAME(I),STATUS="OLD",ACTION="READ")	
      END DO		

      CALL FILEMERGE(MANY,FI,F)	

      END