Skip to content

Commit 68c4355

Browse files
committed
CoordinateSequence: create using external buffer
1 parent 60edf0e commit 68c4355

File tree

10 files changed

+773
-15
lines changed

10 files changed

+773
-15
lines changed

capi/geos_c.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,12 @@ extern "C" {
983983
return GEOSCoordSeq_create_r(handle, size, dims);
984984
}
985985

986+
CoordinateSequence*
987+
GEOSCoordSeq_createFromBuffer(double* buf, unsigned int size, int hasZ, int hasM)
988+
{
989+
return GEOSCoordSeq_createFromBuffer_r(handle, buf, size, hasZ, hasM);
990+
}
991+
986992
CoordinateSequence*
987993
GEOSCoordSeq_copyFromBuffer(const double* buf, unsigned int size, int hasZ, int hasM)
988994
{

capi/geos_c.h.in

+24-3
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,14 @@ extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_create_r(
396396
unsigned int size,
397397
unsigned int dims);
398398

399+
/** \see GEOSCoordSeq_createFromBuffer */
400+
extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_createFromBuffer_r(
401+
GEOSContextHandle_t handle,
402+
double* buf,
403+
unsigned int size,
404+
int hasZ,
405+
int hasM);
406+
399407
/** \see GEOSCoordSeq_copyFromBuffer */
400408
extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_copyFromBuffer_r(
401409
GEOSContextHandle_t handle,
@@ -2023,11 +2031,24 @@ extern void GEOS_DLL GEOSFree(void *buffer);
20232031
extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_create(unsigned int size, unsigned int dims);
20242032

20252033
/**
2026-
* Create a coordinate sequence by copying from a buffer of doubles (XYXY or XYZXYZ)
2034+
* Create a coordinate sequence using from a buffer of interleaved doubles (XYXY, XYZXYZ, etc.)
2035+
* If possible, the CoordinateSequence will use the values directly from the buffer without
2036+
* copying. (Currently, this is supported for XYZ and XYZM buffers only.)
2037+
*
2038+
* \param buf pointer to buffer
2039+
* \param size number of coordinates in the sequence
2040+
* \param hasZ does buffer have Z values?
2041+
* \param hasM does buffer have M values?
2042+
* \return the sequence or NULL on exception
2043+
*/
2044+
extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_createFromBuffer(double* buf, unsigned int size, int hasZ, int hasM);
2045+
2046+
/**
2047+
* Create a coordinate sequence by copying from a buffer of doubles (XYXY, XYZXYZ, etc.)
20272048
* \param buf pointer to buffer
20282049
* \param size number of coordinates in the sequence
20292050
* \param hasZ does buffer have Z values?
2030-
* \param hasM does buffer have M values? (they will be ignored)
2051+
* \param hasM does buffer have M values?
20312052
* \return the sequence or NULL on exception
20322053
*/
20332054
extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_copyFromBuffer(const double* buf, unsigned int size, int hasZ, int hasM);
@@ -2044,7 +2065,7 @@ extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_copyFromBuffer(const double* buf
20442065
extern GEOSCoordSequence GEOS_DLL *GEOSCoordSeq_copyFromArrays(const double* x, const double* y, const double* z, const double* m, unsigned int size);
20452066

20462067
/**
2047-
* Copy the contents of a coordinate sequence to a buffer of doubles (XYXY or XYZXYZ)
2068+
* Copy the contents of a coordinate sequence to a buffer of doubles (XYXY, XYZXYZ, etc.)
20482069
* \param s sequence to copy
20492070
* \param buf buffer to which coordinates should be copied
20502071
* \param hasZ copy Z values to buffer?

capi/geos_ts_c.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -2430,6 +2430,14 @@ extern "C" {
24302430
});
24312431
}
24322432

2433+
CoordinateSequence*
2434+
GEOSCoordSeq_createFromBuffer_r(GEOSContextHandle_t extHandle, double* buf, unsigned int size, int hasZ, int hasM)
2435+
{
2436+
return execute(extHandle, [&]() {
2437+
return new CoordinateSequence(buf, size, hasZ, hasM);
2438+
});
2439+
}
2440+
24332441
CoordinateSequence*
24342442
GEOSCoordSeq_copyFromBuffer_r(GEOSContextHandle_t extHandle, const double* buf, unsigned int size, int hasZ, int hasM)
24352443
{

include/geos/geom/CoordinateSequence.h

+21-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <geos/geom/Coordinate.h> // for applyCoordinateFilter
2121
#include <geos/geom/CoordinateSequenceIterator.h>
22+
#include <geos/util/Vector.h>
2223

2324
#include <cassert>
2425
#include <vector>
@@ -89,12 +90,28 @@ class GEOS_DLL CoordinateSequence {
8990
* are not actually stored in the sequence.
9091
*
9192
* @param size size of the sequence to create
92-
* @param hasz true if the stored
93-
* @param hasm
94-
* @param initialize
93+
* @param hasz true if the sequence should store z values
94+
* @param hasm true if the sequence should store m values
95+
* @param initialize true if the sequence should be initialized to default coordinate values
9596
*/
9697
CoordinateSequence(std::size_t size, bool hasz, bool hasm, bool initialize = true);
9798

99+
/**
100+
* Create a CoordinateSequence from an externally-owned buffer
101+
* of packed Coordinates. If Coordinates are added to the CoordinateSequence
102+
* or the CoordinateSequence requires repacking, the values will
103+
* be copied into a new buffer owned by this CoordinateSeuqnce.
104+
* Code using a CoordinateSequence constructed in this way must not
105+
* attempt to access references to coordinates with dimensions that
106+
* are not actually stored in the sequence.
107+
*
108+
* @param buf buffer of interleaved coordinates
109+
* @param size number of coordinates in the buffer
110+
* @param hasz true if the buffer has z values
111+
* @param hasm true if the buffer has m values
112+
*/
113+
CoordinateSequence(double* buf, std::size_t size, bool hasz, bool hasm);
114+
98115
/**
99116
* Create a CoordinateSequence from a list of XYZ coordinates.
100117
* Code using the sequence may only access references to CoordinateXY
@@ -688,7 +705,7 @@ class GEOS_DLL CoordinateSequence {
688705
}
689706

690707
private:
691-
std::vector<double> m_vect; // Vector to store values
708+
geos::util::Vector<double> m_vect; // Vector to store values
692709

693710
uint8_t m_stride; // Stride of stored values, corresponding to underlying type
694711

include/geos/util/Vector.h

+236
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <cstring>
5+
#include <iterator>
6+
7+
namespace geos {
8+
namespace util {
9+
10+
template<typename T>
11+
class Vector {
12+
13+
public:
14+
Vector() :
15+
m_buf(nullptr),
16+
m_capacity(0),
17+
m_size(0)
18+
{}
19+
20+
Vector(std::size_t sz) :
21+
m_buf(nullptr),
22+
m_capacity(0),
23+
m_size(static_cast<std::uint32_t>(0))
24+
{
25+
resize(sz);
26+
}
27+
28+
Vector(std::size_t sz, T* buf) :
29+
m_buf(buf),
30+
m_capacity(0),
31+
m_size(static_cast<std::uint32_t>(sz))
32+
{}
33+
34+
Vector(const Vector& other) : Vector() {
35+
if (!other.empty()) {
36+
m_buf = make_space(nullptr, other.size());
37+
std::memcpy(m_buf, other.m_buf, other.size()*sizeof(T));
38+
}
39+
}
40+
41+
Vector& operator=(const Vector& other) {
42+
clear();
43+
44+
if (!other.empty()) {
45+
m_buf = make_space(nullptr, other.size());
46+
std::memcpy(m_buf, other.m_buf, other.size()*sizeof(T));
47+
}
48+
49+
return *this;
50+
}
51+
52+
Vector(Vector&& other) :
53+
m_buf(other.m_buf),
54+
m_capacity(other.m_capacity),
55+
m_size(other.m_size)
56+
{
57+
other.m_buf = nullptr;
58+
other.m_capacity = 0;
59+
other.m_size = 0;
60+
}
61+
62+
Vector& operator=(Vector&& other) {
63+
if (owned()) {
64+
delete[] m_buf;
65+
}
66+
67+
m_buf = other.m_buf;
68+
m_capacity = other.m_capacity;
69+
m_size = other.m_size;
70+
other.m_buf = nullptr;
71+
other.m_capacity = 0;
72+
other.m_size = 0;
73+
74+
return *this;
75+
}
76+
77+
~Vector() {
78+
if (owned()) {
79+
delete[] m_buf;
80+
}
81+
}
82+
83+
void push_back(T item) {
84+
growIfNeeded(1);
85+
assert(size() < capacity());
86+
m_buf[m_size++] = item;
87+
}
88+
89+
void pop_back() {
90+
assert(size() > 0);
91+
m_size--;
92+
}
93+
94+
T* make_space(T* pos, std::size_t n) {
95+
auto loc = pos == nullptr ? 0 : pos - begin();
96+
growIfNeeded(n);
97+
pos = begin() + loc;
98+
99+
if (pos != end()) {
100+
auto num_to_move = static_cast<std::size_t>(end() - pos);
101+
std::memmove(pos + n, pos, num_to_move*sizeof(T));
102+
}
103+
m_size += static_cast<std::uint32_t>(n);
104+
105+
return pos;
106+
}
107+
108+
void insert(T* pos, std::size_t n, const T& value) {
109+
pos = make_space(pos, n);
110+
std::fill(pos, pos + n, value);
111+
}
112+
113+
template<typename Iter>
114+
void insert(T* pos, Iter from, Iter to) {
115+
auto n = static_cast<std::size_t>(to - from);
116+
117+
if (from >= begin() && from < end()) {
118+
// from and to may be invalidated
119+
auto from_n = from - begin();
120+
auto to_n = to - begin();
121+
122+
pos = make_space(pos, n);
123+
124+
from = begin() + from_n;
125+
to = begin() + to_n;
126+
} else {
127+
pos = make_space(pos, n);
128+
}
129+
130+
std::copy(from, to, pos);
131+
}
132+
133+
template<typename Iter>
134+
void assign(Iter from, Iter to) {
135+
assert(static_cast<std::size_t>(to - from) <= size());
136+
std::copy(from, to, begin());
137+
}
138+
139+
void reserve(std::size_t sz) {
140+
if (sz <= capacity()) {
141+
return;
142+
}
143+
144+
T* tmp = sz > 0 ? new T[sz] : nullptr;
145+
if (tmp && !empty()) {
146+
std::memcpy(tmp, m_buf, m_size * sizeof(T));
147+
}
148+
if (owned()) {
149+
delete[] m_buf;
150+
}
151+
m_buf = tmp;
152+
m_capacity = static_cast<std::uint32_t>(sz);
153+
}
154+
155+
void resize(std::size_t sz) {
156+
reserve(sz);
157+
m_size = static_cast<std::uint32_t>(sz);
158+
}
159+
160+
void clear() {
161+
m_size = 0;
162+
}
163+
164+
std::size_t capacity() const {
165+
return m_capacity;
166+
}
167+
168+
std::size_t size() const {
169+
return m_size;
170+
}
171+
172+
bool empty() const {
173+
return m_size == 0;
174+
}
175+
176+
bool owned() const {
177+
return data() == nullptr || !(capacity() == 0 && size() > 0);
178+
}
179+
180+
const T& operator[](std::size_t i) const {
181+
return *(data() + i);
182+
}
183+
184+
T& operator[](std::size_t i) {
185+
return *(data() + i);
186+
}
187+
188+
T* release() {
189+
m_capacity = 0;
190+
return m_buf;
191+
}
192+
193+
T* data() {
194+
return m_buf;
195+
}
196+
197+
const T* data() const {
198+
return m_buf;
199+
}
200+
201+
T* begin() {
202+
return data();
203+
};
204+
205+
T* end() {
206+
return data() + size();
207+
}
208+
209+
const T* begin() const {
210+
return data();
211+
};
212+
213+
const T* end() const {
214+
return data() + size();
215+
}
216+
217+
private:
218+
219+
void growIfNeeded(std::size_t num_to_add) {
220+
if (size() + num_to_add > capacity()) {
221+
auto new_capacity = capacity() == 0 ?
222+
std::max(size() + num_to_add, static_cast<std::size_t>(4)) :
223+
static_cast<std::size_t>(static_cast<double>(capacity()) * 1.5);
224+
new_capacity = std::max(new_capacity, capacity() + num_to_add);
225+
reserve(new_capacity);
226+
}
227+
}
228+
229+
T* m_buf;
230+
std::uint32_t m_capacity;
231+
std::uint32_t m_size;
232+
};
233+
234+
235+
}
236+
}

0 commit comments

Comments
 (0)