Skip to content

Commit cd43857

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

File tree

10 files changed

+794
-18
lines changed

10 files changed

+794
-18
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

+22-7
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

@@ -707,9 +724,7 @@ class GEOS_DLL CoordinateSequence {
707724
}
708725

709726
void make_space(std::size_t pos, std::size_t n) {
710-
m_vect.insert(std::next(m_vect.begin(), static_cast<std::ptrdiff_t>(pos * stride())),
711-
m_stride * n,
712-
DoubleNotANumber);
727+
m_vect.make_space(m_vect.begin() + pos * stride(), n * stride());
713728
}
714729

715730
std::uint8_t stride() const {

include/geos/util/Vector.h

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

0 commit comments

Comments
 (0)