Skip to content

Commit 176657b

Browse files
committed
src: add iterator for Object
Refs: #830 Signed-off-by: Darshan Sen <darshan.sen@postman.com>
1 parent 6697c51 commit 176657b

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed

napi-inl.h

+85
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,14 @@ inline Object::PropertyLValue<uint32_t> Object::operator [](uint32_t index) {
11811181
return PropertyLValue<uint32_t>(*this, index);
11821182
}
11831183

1184+
inline Object::PropertyLValue<Value> Object::operator[](Value index) {
1185+
return PropertyLValue<Value>(*this, index);
1186+
}
1187+
1188+
inline Object::PropertyLValue<Value> Object::operator[](Value index) const {
1189+
return PropertyLValue<Value>(*this, index);
1190+
}
1191+
11841192
inline Value Object::operator [](const char* utf8name) const {
11851193
return Get(utf8name);
11861194
}
@@ -1421,6 +1429,83 @@ inline void Object::AddFinalizer(Finalizer finalizeCallback,
14211429
}
14221430
}
14231431

1432+
#ifdef NAPI_CPP_EXCEPTIONS
1433+
inline Object::const_iterator::const_iterator(const Object* object,
1434+
const Type type) {
1435+
_object = object;
1436+
_keys = object->GetPropertyNames();
1437+
_index = type == Type::BEGIN ? 0 : _keys.Length();
1438+
}
1439+
1440+
inline Object::const_iterator Napi::Object::begin() const {
1441+
const_iterator it(this, Object::const_iterator::Type::BEGIN);
1442+
return it;
1443+
}
1444+
1445+
inline Object::const_iterator Napi::Object::end() const {
1446+
const_iterator it(this, Object::const_iterator::Type::END);
1447+
return it;
1448+
}
1449+
1450+
inline Object::const_iterator& Object::const_iterator::operator++() {
1451+
++_index;
1452+
return *this;
1453+
}
1454+
1455+
inline bool Object::const_iterator::operator==(
1456+
const const_iterator& other) const {
1457+
return _index == other._index;
1458+
}
1459+
1460+
inline bool Object::const_iterator::operator!=(
1461+
const const_iterator& other) const {
1462+
return _index != other._index;
1463+
}
1464+
1465+
inline std::pair<Value, Object::PropertyLValue<Value>>
1466+
Object::const_iterator::operator*() const {
1467+
Value key = _keys[_index];
1468+
const PropertyLValue<Value> value = (*_object)[key];
1469+
return {key, value};
1470+
}
1471+
1472+
inline Object::iterator::iterator(Object* object, const Type type) {
1473+
_object = object;
1474+
_keys = object->GetPropertyNames();
1475+
_index = type == Type::BEGIN ? 0 : _keys.Length();
1476+
}
1477+
1478+
inline Object::iterator Napi::Object::begin() {
1479+
iterator it(this, Object::iterator::Type::BEGIN);
1480+
return it;
1481+
}
1482+
1483+
inline Object::iterator Napi::Object::end() {
1484+
iterator it(this, Object::iterator::Type::END);
1485+
return it;
1486+
}
1487+
1488+
inline Object::iterator& Object::iterator::operator++() {
1489+
++_index;
1490+
return *this;
1491+
}
1492+
1493+
inline bool Object::iterator::operator==(const iterator& other) const {
1494+
return _index == other._index;
1495+
}
1496+
1497+
inline bool Object::iterator::operator!=(const iterator& other) const {
1498+
return _index != other._index;
1499+
}
1500+
1501+
inline std::pair<Value, Object::PropertyLValue<Value>>
1502+
Object::iterator::operator*() {
1503+
Value key = _keys[_index];
1504+
const PropertyLValue<Value> value = (*_object)[key];
1505+
return {key, value};
1506+
}
1507+
#endif // NAPI_CPP_EXCEPTIONS
1508+
14241509
#if NAPI_VERSION >= 8
14251510
inline bool Object::Freeze() {
14261511
napi_status status = napi_object_freeze(_env, _value);

napi.h

+71
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,14 @@ namespace Napi {
610610
uint32_t index /// Property / element index
611611
);
612612

613+
/// Gets or sets an indexed property or array element.
614+
PropertyLValue<Value> operator[](Value index /// Property / element index
615+
);
616+
617+
/// Gets or sets an indexed property or array element.
618+
PropertyLValue<Value> operator[](Value index /// Property / element index
619+
) const;
620+
613621
/// Gets a named property.
614622
Value operator [](
615623
const char* utf8name ///< UTF-8 encoded null-terminated property name
@@ -784,6 +792,21 @@ namespace Napi {
784792
inline void AddFinalizer(Finalizer finalizeCallback,
785793
T* data,
786794
Hint* finalizeHint);
795+
796+
#ifdef NAPI_CPP_EXCEPTIONS
797+
class const_iterator;
798+
799+
inline const_iterator begin() const;
800+
801+
inline const_iterator end() const;
802+
803+
class iterator;
804+
805+
inline iterator begin();
806+
807+
inline iterator end();
808+
#endif // NAPI_CPP_EXCEPTIONS
809+
787810
#if NAPI_VERSION >= 8
788811
bool Freeze();
789812
bool Seal();
@@ -824,6 +847,54 @@ namespace Napi {
824847
uint32_t Length() const;
825848
};
826849

850+
#ifdef NAPI_CPP_EXCEPTIONS
851+
class Object::const_iterator {
852+
private:
853+
enum class Type { BEGIN, END };
854+
855+
inline const_iterator(const Object* object, const Type type);
856+
857+
public:
858+
inline const_iterator& operator++();
859+
860+
inline bool operator==(const const_iterator& other) const;
861+
862+
inline bool operator!=(const const_iterator& other) const;
863+
864+
inline std::pair<Value, Object::PropertyLValue<Value>> operator*() const;
865+
866+
private:
867+
const Napi::Object* _object;
868+
Array _keys;
869+
uint32_t _index;
870+
871+
friend class Object;
872+
};
873+
874+
class Object::iterator {
875+
private:
876+
enum class Type { BEGIN, END };
877+
878+
inline iterator(Object* object, const Type type);
879+
880+
public:
881+
inline iterator& operator++();
882+
883+
inline bool operator==(const iterator& other) const;
884+
885+
inline bool operator!=(const iterator& other) const;
886+
887+
inline std::pair<Value, Object::PropertyLValue<Value>> operator*();
888+
889+
private:
890+
Napi::Object* _object;
891+
Array _keys;
892+
uint32_t _index;
893+
894+
friend class Object;
895+
};
896+
#endif // NAPI_CPP_EXCEPTIONS
897+
827898
/// A JavaScript array buffer value.
828899
class ArrayBuffer : public Object {
829900
public:

test/object/object.cc

+16
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,19 @@ Value CreateObjectUsingMagic(const CallbackInfo& info) {
252252
return obj;
253253
}
254254

255+
#ifdef NAPI_CPP_EXCEPTIONS
256+
Value Sum(const CallbackInfo& info) {
257+
Object object = info[0].As<Object>();
258+
int64_t sum = 0;
259+
260+
for (const auto& e : object) {
261+
sum += static_cast<Value>(e.second).As<Number>().Int64Value();
262+
}
263+
264+
return Number::New(info.Env(), sum);
265+
}
266+
#endif // NAPI_CPP_EXCEPTIONS
267+
255268
Value InstanceOf(const CallbackInfo& info) {
256269
Object obj = info[0].As<Object>();
257270
Function constructor = info[1].As<Function>();
@@ -298,6 +311,9 @@ Object InitObject(Env env) {
298311
exports["hasPropertyWithCppStyleString"] = Function::New(env, HasPropertyWithCppStyleString);
299312

300313
exports["createObjectUsingMagic"] = Function::New(env, CreateObjectUsingMagic);
314+
#ifdef NAPI_CPP_EXCEPTIONS
315+
exports["sum"] = Function::New(env, Sum);
316+
#endif // NAPI_CPP_EXCEPTIONS
301317

302318
exports["addFinalizer"] = Function::New(env, AddFinalizer);
303319
exports["addFinalizerWithHint"] = Function::New(env, AddFinalizerWithHint);

test/object/object.js

+42
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,46 @@ function test(binding) {
156156
assert.strictEqual(binding.object.instanceOf({}, Ctor), false);
157157
assert.strictEqual(binding.object.instanceOf(null, Ctor), false);
158158
}
159+
160+
if ('sum' in binding.object) {
161+
{
162+
const obj = {
163+
'-forbid': -0x4B1D,
164+
'-feedcode': -0xFEEDC0DE,
165+
'+office': +0x0FF1CE,
166+
'+forbid': +0x4B1D,
167+
'+deadbeef': +0xDEADBEEF,
168+
'+feedcode': +0xFEEDC0DE,
169+
};
170+
171+
let sum = 0;
172+
for (const key in obj) {
173+
sum += obj[key];
174+
}
175+
176+
assert.strictEqual(binding.object.sum(obj), sum);
177+
}
178+
179+
{
180+
const obj = new Proxy({
181+
'-forbid': -0x4B1D,
182+
'-feedcode': -0xFEEDC0DE,
183+
'+office': +0x0FF1CE,
184+
'+forbid': +0x4B1D,
185+
'+deadbeef': +0xDEADBEEF,
186+
'+feedcode': +0xFEEDC0DE,
187+
}, {
188+
getOwnPropertyDescriptor(target, p) {
189+
throw new Error("getOwnPropertyDescriptor error");
190+
},
191+
ownKeys(target) {
192+
throw new Error("ownKeys error");
193+
},
194+
});
195+
196+
assert.throws(() => {
197+
binding.object.sum(obj);
198+
}, /ownKeys error/);
199+
}
200+
}
159201
}

0 commit comments

Comments
 (0)