#include <xs/uri.h>
#include <xs/export.h>
#include <unordered_map>
#include <panda/uri/all.h>
#include <panda/string_view.h>
using namespace xs;
using namespace xs::uri;
using namespace panda::uri;
using panda::string;
using panda::string_view;
static std::unordered_map<string, Stash> uri_class_map;
static Sv::payload_marker_t data_marker;
struct XsUriData {
XsUriData () : query_cache_rev(0) {}
void sync_query_hash (const URI* uri) {
Hash hash;
if (query_cache) {
hash = query_cache.value<Hash>();
hash.clear();
} else {
hash = Hash::create();
query_cache = Ref::create(hash);
}
auto end = uri->query().cend();
for (auto it = uri->query().cbegin(); it != end; ++it) hash.store(it->first, Simple(it->second));
query_cache_rev = uri->query().rev;
}
Ref query_hash (const URI* uri) {
if (!query_cache || query_cache_rev != uri->query().rev) sync_query_hash(uri);
return query_cache;
}
private:
Ref query_cache;
uint32_t query_cache_rev;
};
static void register_perl_scheme (const string& scheme, const string_view& perl_class) {
uri_class_map[scheme] = Stash(perl_class);
}
Stash xs::uri::get_perl_class (const URI* uri) {
auto it = uri_class_map.find(uri->scheme());
if (it == uri_class_map.end()) return Stash();
else return it->second;
}
void xs::uri::data_attach (Sv& sv) {
void* data = new XsUriData();
Object(sv).payload_attach(data, &data_marker);
}
static int data_free (pTHX_ SV*, MAGIC* mg) {
auto data = (XsUriData*)mg->mg_ptr;
delete data;
return 0;
}
static XsUriData* data_get (SV* sv) {
return (XsUriData*)Object(sv).payload(&data_marker).ptr;
}
static void add_param (URI* uri, const string& key, const Scalar& val, bool replace = false) {
if (val.is_array_ref()) {
Array arr = val;
if (replace) uri->query().erase(key);
auto end = arr.end();
for (auto it = arr.begin(); it != end; ++it) {
if (!*it) continue;
uri->query().emplace(key, xs::in<string>(*it));
}
}
else if (replace) uri->param(key, xs::in<string>(val));
else uri->query().emplace(key, xs::in<string>(val));
}
static void hash2query (Hash& hash, Query* query) {
auto end = hash.end();
for (auto it = hash.begin(); it != end; ++it) {
string key(it->key());
auto val = it->value();
if (val.is_array_ref()) {
Array arr = val;
auto end = arr.end();
for (auto it = arr.begin(); it != end; ++it) {
if (!*it) continue;
query->emplace(key, xs::in<string>(*it));
}
}
else query->emplace(key, xs::in<string>(val));
}
}
static void add_query_hash (URI* uri, Hash& hash, bool replace = false) {
if (replace) {
Query query;
hash2query(hash, &query);
uri->query(query);
}
else {
auto end = hash.end();
for (auto it = hash.begin(); it != end; ++it) add_param(uri, string(it->key()), it->value());
}
}
static void add_query_args (URI* uri, SV** sp, I32 items, bool replace = false) {
if (items == 1) {
if (SvROK(*sp)) {
Hash hash = *sp;
if (hash) add_query_hash(uri, hash, replace);
}
else if (replace) uri->query(xs::in<string>(*sp));
else uri->add_query(xs::in<string>(*sp));
}
else {
SV** spe = sp + items;
for (; sp < spe; sp += 2) add_param(uri, xs::in<string>(*sp), *(sp+1), replace);
}
}
MODULE = URI::XS PACKAGE = URI::XS
PROTOTYPES: DISABLE
BOOT {
data_marker.svt_free = data_free;
xs::at_perl_destroy([]{
uri_class_map.clear();
});
}
URIx uri (string url = string(), int flags = 0) {
RETVAL = URI::create(url, flags);
}
void register_scheme (string scheme, string_view perl_class) {
register_perl_scheme(scheme, perl_class);
}
uint64_t bench_parse (string str, int flags = 0) {
RETVAL = 0;
for (int i = 0; i < 1000; ++i) {
URI u(str, flags);
RETVAL += u.path().length();
}
}
void test_parse (string str) {
auto uri = URI(str);
printf("scheme=%s\n", uri.scheme().c_str());
printf("userinfo=%s\n", uri.user_info().c_str());
printf("host=%s\n", uri.host().c_str());
printf("port=%d\n", uri.port());
printf("path=%s\n", uri.path().c_str());
printf("query=%s\n", uri.raw_query().c_str());
printf("fragment=%s\n", uri.fragment().c_str());
}
void bench_parse_query (string str) {
URI u;
for (int i = 0; i < 1000; ++i) {
u.query_string(str);
u.query();
}
}
uint64_t bench_encode_uri_component (string_view str) {
RETVAL = 0;
auto dest = (char*)alloca(str.length() * 3);
for (int i = 0; i < 1000; ++i) {
encode_uri_component(str, dest);
}
}
uint64_t bench_decode_uri_component (string_view str) {
RETVAL = 0;
auto dest = (char*)alloca(str.length());
for (int i = 0; i < 1000; ++i) {
decode_uri_component(str, dest);
}
}
INCLUDE: encode.xsi
INCLUDE: URI.xsi
INCLUDE: schemas.xsi
INCLUDE: cloning.xsi