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.

114 lines
2.4 KiB

  1. /* Accumulator struct implementation */
  2. #include "Python.h"
  3. static PyObject *
  4. join_list_unicode(PyObject *lst)
  5. {
  6. /* return ''.join(lst) */
  7. PyObject *sep, *ret;
  8. sep = PyUnicode_FromStringAndSize("", 0);
  9. ret = PyUnicode_Join(sep, lst);
  10. Py_DECREF(sep);
  11. return ret;
  12. }
  13. int
  14. _PyAccu_Init(_PyAccu *acc)
  15. {
  16. /* Lazily allocated */
  17. acc->large = NULL;
  18. acc->small = PyList_New(0);
  19. if (acc->small == NULL)
  20. return -1;
  21. return 0;
  22. }
  23. static int
  24. flush_accumulator(_PyAccu *acc)
  25. {
  26. Py_ssize_t nsmall = PyList_GET_SIZE(acc->small);
  27. if (nsmall) {
  28. int ret;
  29. PyObject *joined;
  30. if (acc->large == NULL) {
  31. acc->large = PyList_New(0);
  32. if (acc->large == NULL)
  33. return -1;
  34. }
  35. joined = join_list_unicode(acc->small);
  36. if (joined == NULL)
  37. return -1;
  38. if (PyList_SetSlice(acc->small, 0, nsmall, NULL)) {
  39. Py_DECREF(joined);
  40. return -1;
  41. }
  42. ret = PyList_Append(acc->large, joined);
  43. Py_DECREF(joined);
  44. return ret;
  45. }
  46. return 0;
  47. }
  48. int
  49. _PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode)
  50. {
  51. Py_ssize_t nsmall;
  52. assert(PyUnicode_Check(unicode));
  53. if (PyList_Append(acc->small, unicode))
  54. return -1;
  55. nsmall = PyList_GET_SIZE(acc->small);
  56. /* Each item in a list of unicode objects has an overhead (in 64-bit
  57. * builds) of:
  58. * - 8 bytes for the list slot
  59. * - 56 bytes for the header of the unicode object
  60. * that is, 64 bytes. 100000 such objects waste more than 6MB
  61. * compared to a single concatenated string.
  62. */
  63. if (nsmall < 100000)
  64. return 0;
  65. return flush_accumulator(acc);
  66. }
  67. PyObject *
  68. _PyAccu_FinishAsList(_PyAccu *acc)
  69. {
  70. int ret;
  71. PyObject *res;
  72. ret = flush_accumulator(acc);
  73. Py_CLEAR(acc->small);
  74. if (ret) {
  75. Py_CLEAR(acc->large);
  76. return NULL;
  77. }
  78. res = acc->large;
  79. acc->large = NULL;
  80. return res;
  81. }
  82. PyObject *
  83. _PyAccu_Finish(_PyAccu *acc)
  84. {
  85. PyObject *list, *res;
  86. if (acc->large == NULL) {
  87. list = acc->small;
  88. acc->small = NULL;
  89. }
  90. else {
  91. list = _PyAccu_FinishAsList(acc);
  92. if (!list)
  93. return NULL;
  94. }
  95. res = join_list_unicode(list);
  96. Py_DECREF(list);
  97. return res;
  98. }
  99. void
  100. _PyAccu_Destroy(_PyAccu *acc)
  101. {
  102. Py_CLEAR(acc->small);
  103. Py_CLEAR(acc->large);
  104. }