You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.8 KiB

  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. * bytes-like.
  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 (PyBytes_CheckExact(item)) {
  57. /* Fast path. */
  58. Py_INCREF(item);
  59. buffers[i].obj = item;
  60. buffers[i].buf = PyBytes_AS_STRING(item);
  61. buffers[i].len = PyBytes_GET_SIZE(item);
  62. }
  63. else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) {
  64. PyErr_Format(PyExc_TypeError,
  65. "sequence item %zd: expected a bytes-like object, "
  66. "%.80s found",
  67. i, Py_TYPE(item)->tp_name);
  68. goto error;
  69. }
  70. nbufs = i + 1; /* for error cleanup */
  71. itemlen = buffers[i].len;
  72. if (itemlen > PY_SSIZE_T_MAX - sz) {
  73. PyErr_SetString(PyExc_OverflowError,
  74. "join() result is too long");
  75. goto error;
  76. }
  77. sz += itemlen;
  78. if (i != 0) {
  79. if (seplen > PY_SSIZE_T_MAX - sz) {
  80. PyErr_SetString(PyExc_OverflowError,
  81. "join() result is too long");
  82. goto error;
  83. }
  84. sz += seplen;
  85. }
  86. if (seqlen != PySequence_Fast_GET_SIZE(seq)) {
  87. PyErr_SetString(PyExc_RuntimeError,
  88. "sequence changed size during iteration");
  89. goto error;
  90. }
  91. }
  92. /* Allocate result space. */
  93. res = STRINGLIB_NEW(NULL, sz);
  94. if (res == NULL)
  95. goto error;
  96. /* Catenate everything. */
  97. p = STRINGLIB_STR(res);
  98. if (!seplen) {
  99. /* fast path */
  100. for (i = 0; i < nbufs; i++) {
  101. Py_ssize_t n = buffers[i].len;
  102. char *q = buffers[i].buf;
  103. Py_MEMCPY(p, q, n);
  104. p += n;
  105. }
  106. goto done;
  107. }
  108. for (i = 0; i < nbufs; i++) {
  109. Py_ssize_t n;
  110. char *q;
  111. if (i) {
  112. Py_MEMCPY(p, sepstr, seplen);
  113. p += seplen;
  114. }
  115. n = buffers[i].len;
  116. q = buffers[i].buf;
  117. Py_MEMCPY(p, q, n);
  118. p += n;
  119. }
  120. goto done;
  121. error:
  122. res = NULL;
  123. done:
  124. Py_DECREF(seq);
  125. for (i = 0; i < nbufs; i++)
  126. PyBuffer_Release(&buffers[i]);
  127. if (buffers != static_buffers)
  128. PyMem_FREE(buffers);
  129. return res;
  130. }
  131. #undef NB_STATIC_BUFFERS