PageRenderTime 47ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/Objects/stringlib/join.h

https://bitbucket.org/pombredanne/cpython
C Header | 133 lines | 116 code | 9 blank | 8 comment | 29 complexity | 83094c28b0ad3022c7336f0214a324bb MD5 | raw file
Possible License(s): 0BSD
  1. /* stringlib: bytes joining implementation */
  2. #if STRINGLIB_SIZEOF_CHAR != 1
  3. #error join.h only compatible with byte-wise strings
  4. #endif
  5. Py_LOCAL_INLINE(PyObject *)
  6. STRINGLIB(bytes_join)(PyObject *sep, PyObject *iterable)
  7. {
  8. char *sepstr = STRINGLIB_STR(sep);
  9. const Py_ssize_t seplen = STRINGLIB_LEN(sep);
  10. PyObject *res = NULL;
  11. char *p;
  12. Py_ssize_t seqlen = 0;
  13. Py_ssize_t sz = 0;
  14. Py_ssize_t i, nbufs;
  15. PyObject *seq, *item;
  16. Py_buffer *buffers = NULL;
  17. #define NB_STATIC_BUFFERS 10
  18. Py_buffer static_buffers[NB_STATIC_BUFFERS];
  19. seq = PySequence_Fast(iterable, "can only join an iterable");
  20. if (seq == NULL) {
  21. return NULL;
  22. }
  23. seqlen = PySequence_Fast_GET_SIZE(seq);
  24. if (seqlen == 0) {
  25. Py_DECREF(seq);
  26. return STRINGLIB_NEW(NULL, 0);
  27. }
  28. #ifndef STRINGLIB_MUTABLE
  29. if (seqlen == 1) {
  30. item = PySequence_Fast_GET_ITEM(seq, 0);
  31. if (STRINGLIB_CHECK_EXACT(item)) {
  32. Py_INCREF(item);
  33. Py_DECREF(seq);
  34. return item;
  35. }
  36. }
  37. #endif
  38. if (seqlen > NB_STATIC_BUFFERS) {
  39. buffers = PyMem_NEW(Py_buffer, seqlen);
  40. if (buffers == NULL) {
  41. Py_DECREF(seq);
  42. PyErr_NoMemory();
  43. return NULL;
  44. }
  45. }
  46. else {
  47. buffers = static_buffers;
  48. }
  49. /* Here is the general case. Do a pre-pass to figure out the total
  50. * amount of space we'll need (sz), and see whether all arguments are
  51. * buffer-compatible.
  52. */
  53. for (i = 0, nbufs = 0; i < seqlen; i++) {
  54. Py_ssize_t itemlen;
  55. item = PySequence_Fast_GET_ITEM(seq, i);
  56. if (_getbuffer(item, &buffers[i]) < 0) {
  57. PyErr_Format(PyExc_TypeError,
  58. "sequence item %zd: expected bytes, bytearray, "
  59. "or an object with the buffer interface, %.80s found",
  60. i, Py_TYPE(item)->tp_name);
  61. goto error;
  62. }
  63. nbufs = i + 1; /* for error cleanup */
  64. itemlen = buffers[i].len;
  65. if (itemlen > PY_SSIZE_T_MAX - sz) {
  66. PyErr_SetString(PyExc_OverflowError,
  67. "join() result is too long");
  68. goto error;
  69. }
  70. sz += itemlen;
  71. if (i != 0) {
  72. if (seplen > PY_SSIZE_T_MAX - sz) {
  73. PyErr_SetString(PyExc_OverflowError,
  74. "join() result is too long");
  75. goto error;
  76. }
  77. sz += seplen;
  78. }
  79. if (seqlen != PySequence_Fast_GET_SIZE(seq)) {
  80. PyErr_SetString(PyExc_RuntimeError,
  81. "sequence changed size during iteration");
  82. goto error;
  83. }
  84. }
  85. /* Allocate result space. */
  86. res = STRINGLIB_NEW(NULL, sz);
  87. if (res == NULL)
  88. goto error;
  89. /* Catenate everything. */
  90. p = STRINGLIB_STR(res);
  91. if (!seplen) {
  92. /* fast path */
  93. for (i = 0; i < nbufs; i++) {
  94. Py_ssize_t n = buffers[i].len;
  95. char *q = buffers[i].buf;
  96. Py_MEMCPY(p, q, n);
  97. p += n;
  98. }
  99. goto done;
  100. }
  101. for (i = 0; i < nbufs; i++) {
  102. Py_ssize_t n;
  103. char *q;
  104. if (i) {
  105. Py_MEMCPY(p, sepstr, seplen);
  106. p += seplen;
  107. }
  108. n = buffers[i].len;
  109. q = buffers[i].buf;
  110. Py_MEMCPY(p, q, n);
  111. p += n;
  112. }
  113. goto done;
  114. error:
  115. res = NULL;
  116. done:
  117. Py_DECREF(seq);
  118. for (i = 0; i < nbufs; i++)
  119. PyBuffer_Release(&buffers[i]);
  120. if (buffers != static_buffers)
  121. PyMem_FREE(buffers);
  122. return res;
  123. }
  124. #undef NB_STATIC_BUFFERS