any.c++ (7880B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "any.h" 23 24 #include <kj/debug.h> 25 26 #if !CAPNP_LITE 27 #include "capability.h" 28 #endif // !CAPNP_LITE 29 30 namespace capnp { 31 32 #if !CAPNP_LITE 33 34 kj::Own<ClientHook> PipelineHook::getPipelinedCap(kj::Array<PipelineOp>&& ops) { 35 return getPipelinedCap(ops.asPtr()); 36 } 37 38 kj::Own<ClientHook> AnyPointer::Reader::getPipelinedCap( 39 kj::ArrayPtr<const PipelineOp> ops) const { 40 _::PointerReader pointer = reader; 41 42 for (auto& op: ops) { 43 switch (op.type) { 44 case PipelineOp::Type::NOOP: 45 break; 46 47 case PipelineOp::Type::GET_POINTER_FIELD: 48 pointer = pointer.getStruct(nullptr).getPointerField(bounded(op.pointerIndex) * POINTERS); 49 break; 50 } 51 } 52 53 return pointer.getCapability(); 54 } 55 56 AnyPointer::Pipeline AnyPointer::Pipeline::noop() { 57 auto newOps = kj::heapArray<PipelineOp>(ops.size()); 58 for (auto i: kj::indices(ops)) { 59 newOps[i] = ops[i]; 60 } 61 return Pipeline(hook->addRef(), kj::mv(newOps)); 62 } 63 64 AnyPointer::Pipeline AnyPointer::Pipeline::getPointerField(uint16_t pointerIndex) { 65 auto newOps = kj::heapArray<PipelineOp>(ops.size() + 1); 66 for (auto i: kj::indices(ops)) { 67 newOps[i] = ops[i]; 68 } 69 auto& newOp = newOps[ops.size()]; 70 newOp.type = PipelineOp::GET_POINTER_FIELD; 71 newOp.pointerIndex = pointerIndex; 72 73 return Pipeline(hook->addRef(), kj::mv(newOps)); 74 } 75 76 kj::Own<ClientHook> AnyPointer::Pipeline::asCap() { 77 return hook->getPipelinedCap(ops); 78 } 79 80 #endif // !CAPNP_LITE 81 82 Equality AnyStruct::Reader::equals(AnyStruct::Reader right) const { 83 auto dataL = getDataSection(); 84 size_t dataSizeL = dataL.size(); 85 while(dataSizeL > 0 && dataL[dataSizeL - 1] == 0) { 86 -- dataSizeL; 87 } 88 89 auto dataR = right.getDataSection(); 90 size_t dataSizeR = dataR.size(); 91 while(dataSizeR > 0 && dataR[dataSizeR - 1] == 0) { 92 -- dataSizeR; 93 } 94 95 if(dataSizeL != dataSizeR) { 96 return Equality::NOT_EQUAL; 97 } 98 99 if(0 != memcmp(dataL.begin(), dataR.begin(), dataSizeL)) { 100 return Equality::NOT_EQUAL; 101 } 102 103 auto ptrsL = getPointerSection(); 104 size_t ptrsSizeL = ptrsL.size(); 105 while (ptrsSizeL > 0 && ptrsL[ptrsSizeL - 1].isNull()) { 106 -- ptrsSizeL; 107 } 108 109 auto ptrsR = right.getPointerSection(); 110 size_t ptrsSizeR = ptrsR.size(); 111 while (ptrsSizeR > 0 && ptrsR[ptrsSizeR - 1].isNull()) { 112 -- ptrsSizeR; 113 } 114 115 if(ptrsSizeL != ptrsSizeR) { 116 return Equality::NOT_EQUAL; 117 } 118 119 size_t i = 0; 120 121 auto eqResult = Equality::EQUAL; 122 for (; i < ptrsSizeL; i++) { 123 auto l = ptrsL[i]; 124 auto r = ptrsR[i]; 125 switch(l.equals(r)) { 126 case Equality::EQUAL: 127 break; 128 case Equality::NOT_EQUAL: 129 return Equality::NOT_EQUAL; 130 case Equality::UNKNOWN_CONTAINS_CAPS: 131 eqResult = Equality::UNKNOWN_CONTAINS_CAPS; 132 break; 133 default: 134 KJ_UNREACHABLE; 135 } 136 } 137 138 return eqResult; 139 } 140 141 kj::StringPtr KJ_STRINGIFY(Equality res) { 142 switch(res) { 143 case Equality::NOT_EQUAL: 144 return "NOT_EQUAL"; 145 case Equality::EQUAL: 146 return "EQUAL"; 147 case Equality::UNKNOWN_CONTAINS_CAPS: 148 return "UNKNOWN_CONTAINS_CAPS"; 149 } 150 KJ_UNREACHABLE; 151 } 152 153 Equality AnyList::Reader::equals(AnyList::Reader right) const { 154 if(size() != right.size()) { 155 return Equality::NOT_EQUAL; 156 } 157 158 if (getElementSize() != right.getElementSize()) { 159 return Equality::NOT_EQUAL; 160 } 161 162 auto eqResult = Equality::EQUAL; 163 switch(getElementSize()) { 164 case ElementSize::VOID: 165 case ElementSize::BIT: 166 case ElementSize::BYTE: 167 case ElementSize::TWO_BYTES: 168 case ElementSize::FOUR_BYTES: 169 case ElementSize::EIGHT_BYTES: { 170 size_t cmpSize = getRawBytes().size(); 171 172 if (getElementSize() == ElementSize::BIT && size() % 8 != 0) { 173 // The list does not end on a byte boundary. We need special handling for the final 174 // byte because we only care about the bits that are actually elements of the list. 175 176 uint8_t mask = (1 << (size() % 8)) - 1; // lowest size() bits set 177 if ((getRawBytes()[cmpSize - 1] & mask) != (right.getRawBytes()[cmpSize - 1] & mask)) { 178 return Equality::NOT_EQUAL; 179 } 180 cmpSize -= 1; 181 } 182 183 if (memcmp(getRawBytes().begin(), right.getRawBytes().begin(), cmpSize) == 0) { 184 return Equality::EQUAL; 185 } else { 186 return Equality::NOT_EQUAL; 187 } 188 } 189 case ElementSize::POINTER: 190 case ElementSize::INLINE_COMPOSITE: { 191 auto llist = as<List<AnyStruct>>(); 192 auto rlist = right.as<List<AnyStruct>>(); 193 for(size_t i = 0; i < size(); i++) { 194 switch(llist[i].equals(rlist[i])) { 195 case Equality::EQUAL: 196 break; 197 case Equality::NOT_EQUAL: 198 return Equality::NOT_EQUAL; 199 case Equality::UNKNOWN_CONTAINS_CAPS: 200 eqResult = Equality::UNKNOWN_CONTAINS_CAPS; 201 break; 202 default: 203 KJ_UNREACHABLE; 204 } 205 } 206 return eqResult; 207 } 208 } 209 KJ_UNREACHABLE; 210 } 211 212 Equality AnyPointer::Reader::equals(AnyPointer::Reader right) const { 213 if(getPointerType() != right.getPointerType()) { 214 return Equality::NOT_EQUAL; 215 } 216 switch(getPointerType()) { 217 case PointerType::NULL_: 218 return Equality::EQUAL; 219 case PointerType::STRUCT: 220 return getAs<AnyStruct>().equals(right.getAs<AnyStruct>()); 221 case PointerType::LIST: 222 return getAs<AnyList>().equals(right.getAs<AnyList>()); 223 case PointerType::CAPABILITY: 224 return Equality::UNKNOWN_CONTAINS_CAPS; 225 } 226 // There aren't currently any other types of pointers 227 KJ_UNREACHABLE; 228 } 229 230 bool AnyPointer::Reader::operator==(AnyPointer::Reader right) const { 231 switch(equals(right)) { 232 case Equality::EQUAL: 233 return true; 234 case Equality::NOT_EQUAL: 235 return false; 236 case Equality::UNKNOWN_CONTAINS_CAPS: 237 KJ_FAIL_REQUIRE( 238 "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case"); 239 } 240 KJ_UNREACHABLE; 241 } 242 243 bool AnyStruct::Reader::operator==(AnyStruct::Reader right) const { 244 switch(equals(right)) { 245 case Equality::EQUAL: 246 return true; 247 case Equality::NOT_EQUAL: 248 return false; 249 case Equality::UNKNOWN_CONTAINS_CAPS: 250 KJ_FAIL_REQUIRE( 251 "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case"); 252 } 253 KJ_UNREACHABLE; 254 } 255 256 bool AnyList::Reader::operator==(AnyList::Reader right) const { 257 switch(equals(right)) { 258 case Equality::EQUAL: 259 return true; 260 case Equality::NOT_EQUAL: 261 return false; 262 case Equality::UNKNOWN_CONTAINS_CAPS: 263 KJ_FAIL_REQUIRE( 264 "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case"); 265 } 266 KJ_UNREACHABLE; 267 } 268 269 } // namespace capnp