pelib  2.0.0
include/pelib/fifo.c
Go to the documentation of this file.
00001 /*
00002  * fifo.c
00003  *
00004  *  Created on: 26 Jan 2012
00005  *  Copyright 2012 Nicolas Melot
00006  *
00007  * This file is part of pelib.
00008  * 
00009  *     pelib is free software: you can redistribute it and/or modify
00010  *     it under the terms of the GNU General Public License as published by
00011  *     the Free Software Foundation, either version 3 of the License, or
00012  *     (at your option) any later version.
00013  * 
00014  *     pelib is distributed in the hope that it will be useful,
00015  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *     GNU General Public License for more details.
00018  * 
00019  *     You should have received a copy of the GNU General Public License
00020  *     along with pelib. If not, see <http://www.gnu.org/licenses/>.
00021  * 
00022  */
00023 
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <stddef.h>
00028 
00029 #ifndef CFIFO_T
00030 #error Using generic fifo without a type
00031 #endif
00032 
00033 // Aliases for static functions
00034 #define state(elem) PELIB_CONCAT_3(cfifo_, elem, _state)
00035 #define is_in_content(elem) PELIB_CONCAT_2(is_in_content_, elem)
00036 #define continuous_read_length(elem) PELIB_CONCAT_2(continuous_read_length_, elem)
00037 static size_t continuous_read_length(CFIFO_T)(cfifo_t(CFIFO_T) *fifo);
00038 #define continuous_write_length(elem) PELIB_CONCAT_2(continuous_write_length_, elem)
00039 static size_t continuous_write_length(CFIFO_T)(cfifo_t(CFIFO_T) *fifo);
00040 
00041 #define CFIFO_EMPTY "[]"
00042 #define CFIFO_SEPARATOR ":"
00043 #define CFIFO_BEGIN "["
00044 #define CFIFO_END "]"
00045 
00046 #ifdef debug
00047 #undef debug
00048 #undef debug_addr
00049 #undef debug_int
00050 #undef debug_size_t
00051 #endif
00052 
00053 #if 10
00054 #define debug(var) printf("[%s:%s:%d] %s = \"%s\"\n", __FILE__, __FUNCTION__, __LINE__, #var, var); fflush(NULL)
00055 #define debug_addr(var) printf("[%s:%s:%d] %s = \"%p\"\n", __FILE__, __FUNCTION__, __LINE__, #var, var); fflush(NULL)
00056 #define debug_int(var) printf("[%s:%s:%d] %s = \"%d\"\n", __FILE__, __FUNCTION__, __LINE__, #var, var); fflush(NULL)
00057 #define debug_size_t(var) printf("[%s:%s:%d] %s = \"%zu\"\n", __FILE__, __FUNCTION__, __LINE__, #var, (size_t)(var)); fflush(NULL)
00058 #else
00059 #define debug(var)
00060 #define debug_addr(var)
00061 #define debug_int(var)
00062 #define debug_size_t(var)
00063 #endif
00064 
00065 enum state
00066 {
00067   NORMAL, REVERSE, EMPTY, FULL
00068 };
00069 typedef enum state state_t;
00070 
00071 int
00072 pelib_alloc_buffer(cfifo_t(CFIFO_T))(cfifo_t(CFIFO_T)* cfifo, size_t capacity)
00073 {
00074         cfifo->buffer = (CFIFO_T*)malloc(sizeof(CFIFO_T) * capacity);
00075         cfifo->capacity = capacity;
00076 
00077         return 1;
00078 }
00079 
00080 cfifo_t(CFIFO_T)*
00081 pelib_alloc_struct(cfifo_t(CFIFO_T))()
00082 {
00083         cfifo_t(CFIFO_T) *fifo;
00084         fifo = (cfifo_t(CFIFO_T)*)malloc(sizeof(cfifo_t(CFIFO_T)));
00085 
00086         return fifo;
00087 }
00088 
00089 cfifo_t(CFIFO_T)*
00090 pelib_alloc_collection(cfifo_t(CFIFO_T))(size_t size)
00091 {
00092         cfifo_t(CFIFO_T) *fifo;
00093         fifo = pelib_alloc_struct(cfifo_t(CFIFO_T))();
00094         if(fifo != NULL)
00095         {
00096                 if(pelib_alloc_buffer(cfifo_t(CFIFO_T))(fifo, size) == 0)
00097                 {
00098                         pelib_free_struct(cfifo_t(CFIFO_T))(fifo);
00099                         return NULL;
00100                 }
00101         }
00102                 
00103 
00104         return fifo;
00105 }
00106 
00107 int
00108 pelib_init(cfifo_t(CFIFO_T))(cfifo_t(CFIFO_T)* fifo)
00109 {
00110         fifo->last_op = PELIB_CFIFO_POP;
00111         fifo->read = 0;
00112         fifo->write = 0;
00113 
00114         return 1;
00115 }
00116 
00117 int
00118 pelib_free(cfifo_t(CFIFO_T))(cfifo_t(CFIFO_T)* fifo)
00119 {
00120         pelib_free_buffer(cfifo_t(CFIFO_T))(fifo);
00121         return pelib_free_struct(cfifo_t(CFIFO_T))(fifo);
00122 }
00123 
00124 int
00125 pelib_free_struct(cfifo_t(CFIFO_T))(cfifo_t(CFIFO_T)* fifo)
00126 {
00127         free((void*)fifo->buffer);
00128 
00129         return 1;
00130 }
00131 
00132 int
00133 pelib_free_buffer(cfifo_t(CFIFO_T))(cfifo_t(CFIFO_T)* fifo)
00134 {
00135         free(fifo);
00136         return 1;
00137 }
00138 
00139 FILE*
00140 pelib_printf(cfifo_t(CFIFO_T))(FILE* stream, cfifo_t(CFIFO_T) fifo)
00141 {
00142         char* str;
00143         str = pelib_string(cfifo_t(CFIFO_T))(fifo);
00144         printf("%s\n", str);
00145         free(str);
00146 
00147         return stream;
00148 }
00149 
00150 FILE*
00151 pelib_printf_detail(cfifo_t(CFIFO_T))(FILE* stream, cfifo_t(CFIFO_T) fifo, int level)
00152 {
00153         char* str;
00154         str = pelib_string_detail(cfifo_t(CFIFO_T))(fifo, level);
00155         printf("%s\n", str);
00156         free(str);
00157 
00158         return stream;
00159 }
00160 
00161 static state_t
00162 state(CFIFO_T)(cfifo_t(CFIFO_T) *cfifo)
00163 {
00164 /*
00165         debug_size_t((size_t)cfifo->read);
00166         debug_size_t((size_t)cfifo->write);
00167         debug_size_t((size_t)cfifo->last_op);
00168 */
00169     if (cfifo->read == cfifo->write)
00170       {
00171         if (cfifo->last_op == PELIB_CFIFO_POP)
00172           {
00173             return EMPTY;
00174           }
00175         else if (cfifo->last_op == PELIB_CFIFO_PUSH)
00176           {
00177             return FULL;
00178           }
00179         else
00180           {
00181             fprintf(stdout, "[ERROR:%s:%s:%i] Illegal state at fifo %p\n", __FILE__, __FUNCTION__, __LINE__, cfifo);
00182             return EMPTY;
00183           }
00184       }
00185     else if (cfifo->read < cfifo->write)
00186       {
00187         return NORMAL;
00188       }
00189     else
00190       {
00191         return REVERSE;
00192       }
00193   }
00194 
00195 // returns 1 if index is in data area
00196 // returns 3 if index is in position of read index
00197 // returns 7 if index is in both read and write position, and in data area (fifo full)
00198 // returns -7 if index is in both read and write position not in data area (fifo empty)
00199 // returns -1 if index is not in data area
00200 // returns -5 if index is in position of write index but not in data area
00201 // ERRORS:
00202 // returns -2 if index is in position of read index but not read, but is not in data area
00203 // returns 5 if index is in position of write index but not read, but still is in data area
00204 // returns 6 if in both read and write indexes but cannot determine if in data area or not
00205 // returns 0 in case of other errors
00213 static int
00214 is_in_content(CFIFO_T)(cfifo_t(CFIFO_T) *fifo, size_t index)
00215   {
00216     int res;
00217     size_t read;
00218     state_t state;
00219 
00220     read = fifo->read;
00221     state = state(CFIFO_T)(fifo);
00222 
00223     res = 1;
00224     res += index == read ? 2 : 0;
00225     res += index == fifo->write ? 4 : 0;
00226 
00227     switch (state)
00228       {
00229         case NORMAL:
00230         if (index < read || index >= fifo->write)
00231           {
00232             res = -1 * res;
00233           }
00234         break;
00235         case REVERSE:
00236         if (index >= fifo->write && index < read)
00237           {
00238             res = -1 * res;
00239           }
00240         break;
00241         case EMPTY:
00242         res = -1 * res;
00243         break;
00244         case FULL:
00245         // Do nothing
00246         break;
00247         default:
00248         fprintf(stderr, "[ERROR:%s:%s:%i] Illegal cfifo state", __FILE__, __FUNCTION__, __LINE__);
00249         return 0;
00250         break;
00251       }
00252 
00253     return res;
00254   }
00255 
00256 char*
00257 pelib_string(cfifo_t(CFIFO_T))(cfifo_t(CFIFO_T) fifo)
00258   {
00259     return pelib_string_detail(cfifo_t(CFIFO_T))(fifo, 0);
00260   }
00261 
00262 char*
00263 pelib_string_detail(cfifo_t(CFIFO_T))(cfifo_t(CFIFO_T) fifo, int level)
00264 {
00265   char *str, *elem;
00266   unsigned int i;
00267   int status;
00268 
00269   str = (char*)malloc(sizeof(char) * ((PELIB_FIFO_ELEM_MAX_CHAR + 1) * fifo.capacity)
00270       + 4);
00271 
00272   sprintf(str, "[");
00273   for (i = 0; i < fifo.capacity; i++)
00274   {
00275     status = is_in_content(CFIFO_T)(&fifo, i);
00276     if (abs(status) & 2)
00277     {
00278       sprintf(str, "%s>", str);
00279     }
00280     if (abs(status) & 4)
00281     {
00282       sprintf(str, "%s>", str);
00283     }
00284     if(status > 0)
00285     {
00286       elem = pelib_string_detail(CFIFO_T)(fifo.buffer[i], level);
00287       sprintf(str, "%s%s", str, elem);
00288       free(elem);
00289     }
00290     else
00291     {
00292       sprintf(str, "%s.", str);
00293     }
00294     if (i < fifo.capacity - 1)
00295     {
00296       sprintf(str, "%s:", str);
00297     }
00298   }
00299   sprintf(str, "%s]", str);
00300 
00301   return str;
00302 }
00303 
00304 int
00305 pelib_cfifo_push(CFIFO_T)(cfifo_t(CFIFO_T)* fifo, CFIFO_T elem)
00306   {
00307     if (fifo->capacity > 0 && 
00308         state(CFIFO_T)(fifo) != FULL)
00309       {
00310         memcpy((void*)&(fifo->buffer[fifo->write]), &elem, sizeof(CFIFO_T));
00311 
00312         fifo->write = (fifo->write + 1) % fifo->capacity;
00313         fifo->last_op = PELIB_CFIFO_PUSH;
00314 
00315         return 1;
00316       }
00317     else
00318       {
00319         return 0;
00320       }
00321   }
00322 
00323 size_t
00324 pelib_cfifo_fill(CFIFO_T)(cfifo_t(CFIFO_T)* fifo, size_t num)
00325 {
00326         size_t length = pelib_cfifo_capacity(CFIFO_T)(fifo) - pelib_cfifo_length(CFIFO_T)(fifo);
00327         num = length < num ? length : num;
00328 
00329         fifo->write = (fifo->write + num) % fifo->capacity;
00330 
00331         if(num > 0)
00332         {
00333                 fifo->last_op = PELIB_CFIFO_PUSH;
00334         }
00335 
00336         return num;
00337 }
00338 
00339 CFIFO_T*
00340 pelib_cfifo_peekaddr(CFIFO_T)(cfifo_t(CFIFO_T)* fifo, size_t offset, size_t *num, CFIFO_T **addr)
00341   {
00342     if ((fifo->capacity > 0 && offset < pelib_cfifo_length(CFIFO_T)(fifo) && state(CFIFO_T)(fifo) != EMPTY))
00343       {
00344         size_t avail = continuous_read_length(CFIFO_T)(fifo);
00345         if(num != NULL)
00346         {
00347                 *num = avail;
00348         }
00349         if(addr != NULL)
00350         {
00351                 if((fifo->read + offset + avail) % fifo->capacity != fifo->write)
00352                 {
00353                         *addr = (CFIFO_T*)&(fifo->buffer[(fifo->read + offset + avail) % fifo->capacity]);
00354                 }
00355                 else
00356                 {
00357                         *addr = NULL;
00358                 }
00359         }
00360 
00361 /*
00362         debug_size_t(fifo->read);
00363         debug_size_t(offset);
00364         debug_size_t(fifo->read + offset);
00365         debug_size_t((fifo->read + offset) % fifo->capacity);
00366         debug_size_t(fifo->buffer);
00367         debug_size_t(&(fifo->buffer[(fifo->read + offset) % fifo->capacity]));
00368 */
00369         return (CFIFO_T*)&(fifo->buffer[(fifo->read + offset) % fifo->capacity]);
00370       }
00371     else
00372       {
00373         if(num != NULL)
00374         {
00375                 *num = 0;
00376         }
00377         return NULL;
00378       }
00379   }
00380 
00381 CFIFO_T*
00382 pelib_cfifo_writeaddr(CFIFO_T)(cfifo_t(CFIFO_T)* fifo, size_t *num, CFIFO_T **addr)
00383   {
00384     if ((fifo->capacity - pelib_cfifo_length(CFIFO_T)(fifo) > 0) || 1)
00385       {
00386         size_t avail = continuous_write_length(CFIFO_T)(fifo);
00387         if(num != NULL)
00388         {
00389                 *num = avail;
00390         }
00391         if(addr != NULL)
00392         {
00393                 if((fifo->write + avail) % fifo->capacity != fifo->read)
00394                 {
00395                         *addr = (CFIFO_T*)&(fifo->buffer[(fifo->write + avail) % fifo->capacity]);
00396                 }
00397                 else
00398                 {
00399                         *addr = NULL;
00400                 }
00401         }
00402 
00403         return (CFIFO_T*)&(fifo->buffer[fifo->write]);
00404       }
00405     else
00406       {
00407         return NULL;
00408       }
00409   }
00410 
00411 CFIFO_T
00412 pelib_cfifo_pop(CFIFO_T)(cfifo_t(CFIFO_T)* fifo)
00413   {
00414     CFIFO_T *ptr,  res;
00415 
00416     ptr = pelib_cfifo_peekaddr(CFIFO_T)(fifo, 0, NULL, NULL);
00417     if (ptr != NULL)
00418       {
00419         fifo->read = (fifo->read + 1) % fifo->capacity;
00420         fifo->last_op = PELIB_CFIFO_POP;
00421 
00422         res = *ptr;
00423 
00424         return res;
00425       }
00426     else
00427       {
00428         CFIFO_T def;
00429         pelib_init(CFIFO_T)(&def);
00430         return def;
00431       }
00432   }
00433 
00434 size_t
00435 pelib_cfifo_discard(CFIFO_T)(cfifo_t(CFIFO_T) *fifo, size_t num)
00436 {
00437         int length = pelib_cfifo_length(CFIFO_T)(fifo);
00438         num = num < (size_t) length ? num : (size_t)length;
00439 
00440         fifo->read = (fifo->read + num) % fifo->capacity;
00441 
00442         if(num > 0)
00443         {
00444                 fifo->last_op = PELIB_CFIFO_POP;
00445         }
00446 
00447         return num;
00448 }
00449 
00450 CFIFO_T
00451 pelib_cfifo_peek(CFIFO_T)(cfifo_t(CFIFO_T)* cfifo, size_t offset)
00452   {
00453     CFIFO_T *ptr, res;
00454     ptr = pelib_cfifo_peekaddr(CFIFO_T)(cfifo, offset, NULL, NULL);
00455     if (ptr != NULL)
00456       {
00457         res = *ptr;
00458         return res;
00459       }
00460     else
00461       {
00462         CFIFO_T def;
00463         pelib_init(CFIFO_T)(&def);
00464         return def;
00465       }
00466   }
00467 
00468 int
00469 pelib_cfifo_is_full(CFIFO_T)(cfifo_t(CFIFO_T)* cfifo)
00470   {
00471     return state(CFIFO_T)(cfifo) == FULL;
00472   }
00473 
00474 int
00475 pelib_cfifo_is_empty(CFIFO_T)(cfifo_t(CFIFO_T)* cfifo)
00476   {
00477     return state(CFIFO_T)(cfifo) == EMPTY;
00478   }
00479 
00480 size_t
00481 pelib_cfifo_pushmem(CFIFO_T)(cfifo_t(CFIFO_T) *fifo, CFIFO_T* mem, size_t num)
00482 {
00483         size_t left, length, pushed;
00484         switch(state(CFIFO_T)(fifo))
00485         {
00486                 case EMPTY:
00487                 case NORMAL:                    
00488                         left = fifo->capacity - fifo->write;
00489                         length = left < num ? left : num;
00490 
00491                         memcpy((void*)&fifo->buffer[fifo->write], mem, length * sizeof(CFIFO_T));
00492 
00493                         // Record amount of elements pushed
00494                         pushed = length;
00495                         // Update fifo's write pointer
00496                         fifo->write = (fifo->write + length) % fifo->capacity;
00497 
00498                         if(pushed > 0)
00499                         {
00500                                 fifo->last_op = PELIB_CFIFO_PUSH;
00501                         }
00502                         
00503                         // If left was not enough to accomodate the memory buffer to write
00504                         if(left < num)                  
00505                         {
00506                                 // Now we are in the reverse mode, just call the function again
00507                                 pushed += pelib_cfifo_pushmem(CFIFO_T)(fifo, mem + length, num - length);
00508                         }
00509 
00510                         return pushed;
00511                 break;
00512                 
00513                 case FULL:
00514                 case REVERSE:
00515                         // Copy from write to read
00516                         left = fifo->read - fifo->write;
00517                         length = left < num ? left : num;
00518                         memcpy((void*)&(fifo->buffer[fifo->write]), mem, length * sizeof(CFIFO_T));
00519 
00520                         fifo->write += length;
00521                         pushed = length;
00522 
00523                         if(pushed > 0)
00524                         {
00525                                 fifo->last_op = PELIB_CFIFO_PUSH;
00526                         }
00527 
00528                         return pushed;
00529                 break;
00530 
00531                 default:
00532                         return 0;
00533                 break;
00534         }
00535 }
00536 
00537 size_t
00538 pelib_cfifo_popmem(CFIFO_T)(cfifo_t(CFIFO_T) *fifo, CFIFO_T* mem, size_t num)
00539 {
00540         size_t i;
00541         size_t left, length, popped;
00542         volatile int* ptr;
00543         size_t intlength;
00544 
00545         switch(state(CFIFO_T)(fifo))
00546         {
00547                 case FULL:
00548                 case REVERSE:
00549                         // Copy from write to end of buffer
00550                         left = fifo->capacity - fifo->read;
00551                         length = left < num ? left : num;
00552 
00553                         memcpy(mem, (void*)&(fifo->buffer[fifo->read]), length * sizeof(CFIFO_T));
00554                         
00555                         intlength = (length * sizeof(CFIFO_T)) / sizeof(int) ;
00556                         ptr = (volatile int*) (&fifo->buffer[fifo->read]);
00557 
00558                         // Record amount of elements pushed
00559                         popped = length;
00560 
00561                         // Update fifo's write pointer
00562                         fifo->read = (fifo->read + length) % fifo->capacity;
00563 
00564                         if(popped > 0)
00565                         {
00566                                 fifo->last_op = PELIB_CFIFO_POP;
00567                         }
00568                         
00569                         // If left was not enough to accomodate the memory buffer to write
00570                         if(left < num)
00571                         {
00572                                 // Now we are in the reverse mode, just call the function again
00573                                 popped += pelib_cfifo_popmem(CFIFO_T)(fifo, mem + length, num - length);
00574                         }
00575 
00576                         return popped;
00577                 break;
00578                 
00579                 case EMPTY:
00580                 case NORMAL:
00581                         // Copy from write to read
00582                         left = fifo->write - fifo->read;
00583                         length = left < num ? left : num;
00584                         memcpy(mem, (void*)&(fifo->buffer[fifo->read]), length * sizeof(CFIFO_T));
00585                         
00586                         intlength = (length * sizeof(CFIFO_T)) / sizeof(int) ;
00587 
00588                         ptr = (volatile int*) (&fifo->buffer[fifo->read]);
00589                         fifo->read += length;
00590                         popped = length;
00591 
00592                         if(popped > 0)
00593                         {
00594                                 fifo->last_op = PELIB_CFIFO_POP;
00595                         }
00596 
00597                         return popped;
00598                 break;
00599 
00600                 default:
00601                         return 0;
00602                 break;
00603         }
00604 }
00605 
00606 size_t
00607 pelib_cfifo_peekmem(CFIFO_T)(cfifo_t(CFIFO_T)* fifo, CFIFO_T* mem, size_t num, size_t offset)
00608 {
00609         size_t left, length;
00610         cfifo_t(CFIFO_T) copy = *fifo;
00611         copy.read = (copy.read + offset) % copy.capacity;
00612 
00613         switch(state(CFIFO_T)(&copy))
00614         {
00615                 case FULL:
00616                 case REVERSE:
00617                         // Copy from write to end of buffer
00618                         left = copy.capacity - copy.read;
00619                         length = left < num ? left : num;
00620 
00621                         memcpy(mem, (void*)&(copy.buffer[copy.read]), length * sizeof(CFIFO_T));
00622 
00623                         // If left was not enough to accomodate the memory buffer to write
00624                         if((left) < num && left > 0)
00625                         {
00626                                 // Now we are in the reverse mode, just call the function again
00627                                 length += pelib_cfifo_peekmem(CFIFO_T)(&copy, mem + length, num - length, length);
00628                         }
00629 
00630                         return length;
00631                 break;
00632                 
00633                 case EMPTY:
00634                 case NORMAL:
00635                         // Copy from write to read
00636                         left = copy.write - copy.read;
00637                         length = left < num ? left : num;
00638 
00639                         memcpy(mem, (void*)&(copy.buffer[copy.read]), length * sizeof(CFIFO_T));
00640 
00641                         return length;
00642                 break;
00643 
00644                 default:
00645                         return 0;
00646                 break;
00647         }
00648 }
00649 
00650 static
00651 size_t
00652 continuous_read_length(CFIFO_T)(cfifo_t(CFIFO_T)* fifo)
00653 {
00654         switch(state(CFIFO_T)(fifo))
00655         {
00656                 case FULL:
00657                 case REVERSE:
00658                         return fifo->capacity - fifo->read;
00659                 break;
00660                 
00661                 case EMPTY:
00662                         return 0;
00663                 break;
00664                 case NORMAL:
00665                         return fifo->write - fifo->read;
00666                 break;
00667 
00668                 default:
00669                         return -1;
00670                 break;
00671         }
00672 }
00673 
00674 static
00675 size_t
00676 continuous_write_length(CFIFO_T)(cfifo_t(CFIFO_T)* fifo)
00677 {
00678         switch(state(CFIFO_T)(fifo))
00679         {
00680                 case FULL:
00681                         return 0;
00682                 break;
00683                 case REVERSE:
00684                         return fifo->read - fifo->write;
00685                 break;
00686                 
00687                 case EMPTY:
00688                 case NORMAL:
00689                         return fifo->capacity - fifo->write;
00690                 break;
00691 
00692                 default:
00693                         return -1;
00694                 break;
00695         }
00696 }
00697 
00698 size_t
00699 pelib_cfifo_popfifo(CFIFO_T)(cfifo_t(CFIFO_T)* src, cfifo_t(CFIFO_T)* tgt, size_t num)
00700 {
00701         size_t requested = num;
00702 
00703         while(num > 0 && !pelib_cfifo_is_empty(CFIFO_T)(src) && !pelib_cfifo_is_full(CFIFO_T)(tgt))
00704         {
00705                 size_t readl = continuous_read_length(CFIFO_T)(src);
00706                 volatile size_t writel = continuous_write_length(CFIFO_T)(tgt);
00707                 size_t length = readl < writel ? readl : writel;
00708                 length = num < length ? num : length;
00709                 memcpy((void*)&(tgt->buffer[tgt->write]), (void*)&(src->buffer[src->read]), length * sizeof(CFIFO_T));
00710                 num -= length;
00711                 pelib_cfifo_discard(CFIFO_T)(src, length);
00712                 pelib_cfifo_fill(CFIFO_T)(tgt, length);
00713         }
00714 
00715         return requested - num;
00716 }
00717 
00718 size_t
00719 pelib_cfifo_length(CFIFO_T)(cfifo_t(CFIFO_T) *cfifo)
00720 {
00721         switch(state(CFIFO_T)(cfifo))
00722         {
00723                 case EMPTY:
00724                         return 0;
00725                 break;
00726                 case NORMAL:
00727                         return cfifo->write - cfifo->read;
00728                 break;
00729                 case REVERSE:
00730                         return cfifo->capacity - (cfifo->read - cfifo->write);
00731                 break;
00732                 case FULL:
00733                         return cfifo->capacity;
00734                 break;
00735         }
00736 
00737         return 0;
00738 }
00739 
00740 CFIFO_T
00741 pelib_cfifo_last(CFIFO_T)(cfifo_t(CFIFO_T) *cfifo)
00742 {       
00743         size_t length = pelib_cfifo_length(CFIFO_T)(cfifo);
00744 
00745         if(pelib_cfifo_length(CFIFO_T)(cfifo) <= 0)
00746         {  
00747                 CFIFO_T def;
00748                 pelib_init(CFIFO_T)(&def);
00749                 return def;
00750         }
00751         else
00752         {
00753                 CFIFO_T* ptr = pelib_cfifo_peekaddr(CFIFO_T)(cfifo, length - 1, NULL, NULL);
00754                 return *ptr;
00755         }
00756 }
00757 
00758 size_t
00759 pelib_cfifo_capacity(CFIFO_T)(cfifo_t(CFIFO_T)* cfifo)
00760 {
00761         return cfifo->capacity;
00762 }
00763